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 */ 217563SPrasad.Singamsetty@Sun.COM 221709Smlf /* 23*11896SShidokht.Yadegari@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 241709Smlf * Use is subject to license terms. 251709Smlf */ 261709Smlf 271709Smlf #include <sys/scsi/scsi.h> 281709Smlf #include <sys/dktp/cm.h> 291709Smlf #include <sys/dktp/quetypes.h> 301709Smlf #include <sys/dktp/queue.h> 311709Smlf #include <sys/dktp/fctypes.h> 321709Smlf #include <sys/dktp/flowctrl.h> 331709Smlf #include <sys/dktp/cmdev.h> 341709Smlf #include <sys/dkio.h> 351709Smlf #include <sys/dktp/tgdk.h> 361709Smlf #include <sys/dktp/dadk.h> 371709Smlf #include <sys/dktp/bbh.h> 381709Smlf #include <sys/dktp/altsctr.h> 391709Smlf #include <sys/dktp/cmdk.h> 401709Smlf 411709Smlf #include <sys/stat.h> 421709Smlf #include <sys/vtoc.h> 431709Smlf #include <sys/file.h> 441709Smlf #include <sys/dktp/dadkio.h> 451709Smlf #include <sys/aio_req.h> 461709Smlf 471709Smlf #include <sys/cmlb.h> 481709Smlf 491709Smlf /* 501709Smlf * Local Static Data 511709Smlf */ 521709Smlf #ifdef CMDK_DEBUG 531709Smlf #define DENT 0x0001 541709Smlf #define DIO 0x0002 551709Smlf 561709Smlf static int cmdk_debug = DIO; 571709Smlf #endif 581709Smlf 591709Smlf #ifndef TRUE 601709Smlf #define TRUE 1 611709Smlf #endif 621709Smlf 631709Smlf #ifndef FALSE 641709Smlf #define FALSE 0 651709Smlf #endif 661709Smlf 671709Smlf /* 681709Smlf * NDKMAP is the base number for accessing the fdisk partitions. 691709Smlf * c?d?p0 --> cmdk@?,?:q 701709Smlf */ 711709Smlf #define PARTITION0_INDEX (NDKMAP + 0) 721709Smlf 731709Smlf #define DKTP_DATA (dkp->dk_tgobjp)->tg_data 741709Smlf #define DKTP_EXT (dkp->dk_tgobjp)->tg_ext 751709Smlf 768863SEdward.Pilatowicz@Sun.COM void *cmdk_state; 771709Smlf 781709Smlf /* 791709Smlf * the cmdk_attach_mutex protects cmdk_max_instance in multi-threaded 801709Smlf * attach situations 811709Smlf */ 821709Smlf static kmutex_t cmdk_attach_mutex; 831709Smlf static int cmdk_max_instance = 0; 841709Smlf 851709Smlf /* 861709Smlf * Panic dumpsys state 871709Smlf * There is only a single flag that is not mutex locked since 881709Smlf * the system is prevented from thread switching and cmdk_dump 891709Smlf * will only be called in a single threaded operation. 901709Smlf */ 911709Smlf static int cmdk_indump; 921709Smlf 931709Smlf /* 941709Smlf * Local Function Prototypes 951709Smlf */ 961709Smlf static int cmdk_create_obj(dev_info_t *dip, struct cmdk *dkp); 971709Smlf static void cmdk_destroy_obj(dev_info_t *dip, struct cmdk *dkp); 981709Smlf static void cmdkmin(struct buf *bp); 991709Smlf static int cmdkrw(dev_t dev, struct uio *uio, int flag); 1001709Smlf static int cmdkarw(dev_t dev, struct aio_req *aio, int flag); 1011709Smlf 1021709Smlf /* 1031709Smlf * Bad Block Handling Functions Prototypes 1041709Smlf */ 1051709Smlf static void cmdk_bbh_reopen(struct cmdk *dkp); 1061709Smlf static opaque_t cmdk_bbh_gethandle(opaque_t bbh_data, struct buf *bp); 1071709Smlf static bbh_cookie_t cmdk_bbh_htoc(opaque_t bbh_data, opaque_t handle); 1081709Smlf static void cmdk_bbh_freehandle(opaque_t bbh_data, opaque_t handle); 1091709Smlf static void cmdk_bbh_close(struct cmdk *dkp); 1101709Smlf static void cmdk_bbh_setalts_idx(struct cmdk *dkp); 1111709Smlf static int cmdk_bbh_bsearch(struct alts_ent *buf, int cnt, daddr32_t key); 1121709Smlf 1131709Smlf static struct bbh_objops cmdk_bbh_ops = { 1141709Smlf nulldev, 1151709Smlf nulldev, 1161709Smlf cmdk_bbh_gethandle, 1171709Smlf cmdk_bbh_htoc, 1181709Smlf cmdk_bbh_freehandle, 1191709Smlf 0, 0 1201709Smlf }; 1211709Smlf 1221709Smlf static int cmdkopen(dev_t *dev_p, int flag, int otyp, cred_t *credp); 1231709Smlf static int cmdkclose(dev_t dev, int flag, int otyp, cred_t *credp); 1241709Smlf static int cmdkstrategy(struct buf *bp); 1251709Smlf static int cmdkdump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk); 1261709Smlf static int cmdkioctl(dev_t, int, intptr_t, int, cred_t *, int *); 1271709Smlf static int cmdkread(dev_t dev, struct uio *uio, cred_t *credp); 1281709Smlf static int cmdkwrite(dev_t dev, struct uio *uio, cred_t *credp); 1291709Smlf static int cmdk_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 1301709Smlf int mod_flags, char *name, caddr_t valuep, int *lengthp); 1311709Smlf static int cmdkaread(dev_t dev, struct aio_req *aio, cred_t *credp); 1321709Smlf static int cmdkawrite(dev_t dev, struct aio_req *aio, cred_t *credp); 1331709Smlf 1341709Smlf /* 1351709Smlf * Device driver ops vector 1361709Smlf */ 1371709Smlf 1381709Smlf static struct cb_ops cmdk_cb_ops = { 1391709Smlf cmdkopen, /* open */ 1401709Smlf cmdkclose, /* close */ 1411709Smlf cmdkstrategy, /* strategy */ 1421709Smlf nodev, /* print */ 1431709Smlf cmdkdump, /* dump */ 1441709Smlf cmdkread, /* read */ 1451709Smlf cmdkwrite, /* write */ 1461709Smlf cmdkioctl, /* ioctl */ 1471709Smlf nodev, /* devmap */ 1481709Smlf nodev, /* mmap */ 1491709Smlf nodev, /* segmap */ 1501709Smlf nochpoll, /* poll */ 1511709Smlf cmdk_prop_op, /* cb_prop_op */ 1521709Smlf 0, /* streamtab */ 1531709Smlf D_64BIT | D_MP | D_NEW, /* Driver comaptibility flag */ 1541709Smlf CB_REV, /* cb_rev */ 1551709Smlf cmdkaread, /* async read */ 1561709Smlf cmdkawrite /* async write */ 1571709Smlf }; 1581709Smlf 1591709Smlf static int cmdkinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 1601709Smlf void **result); 1611709Smlf static int cmdkprobe(dev_info_t *dip); 1621709Smlf static int cmdkattach(dev_info_t *dip, ddi_attach_cmd_t cmd); 1631709Smlf static int cmdkdetach(dev_info_t *dip, ddi_detach_cmd_t cmd); 1641709Smlf 1655295Srandyf static void cmdk_setup_pm(dev_info_t *dip, struct cmdk *dkp); 1665295Srandyf static int cmdkresume(dev_info_t *dip); 1675295Srandyf static int cmdksuspend(dev_info_t *dip); 1685295Srandyf static int cmdkpower(dev_info_t *dip, int component, int level); 1695295Srandyf 1701709Smlf struct dev_ops cmdk_ops = { 1711709Smlf DEVO_REV, /* devo_rev, */ 1721709Smlf 0, /* refcnt */ 1731709Smlf cmdkinfo, /* info */ 1741709Smlf nulldev, /* identify */ 1751709Smlf cmdkprobe, /* probe */ 1761709Smlf cmdkattach, /* attach */ 1771709Smlf cmdkdetach, /* detach */ 1781709Smlf nodev, /* reset */ 1791709Smlf &cmdk_cb_ops, /* driver operations */ 1805295Srandyf (struct bus_ops *)0, /* bus operations */ 1817656SSherry.Moore@Sun.COM cmdkpower, /* power */ 1827656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */ 1831709Smlf }; 1841709Smlf 1851709Smlf /* 1861709Smlf * This is the loadable module wrapper. 1871709Smlf */ 1881709Smlf #include <sys/modctl.h> 1891709Smlf 1908863SEdward.Pilatowicz@Sun.COM #ifndef XPV_HVM_DRIVER 1911709Smlf static struct modldrv modldrv = { 1928863SEdward.Pilatowicz@Sun.COM &mod_driverops, /* Type of module. This one is a driver */ 1937542SRichard.Bean@Sun.COM "Common Direct Access Disk", 1948863SEdward.Pilatowicz@Sun.COM &cmdk_ops, /* driver ops */ 1951709Smlf }; 1961709Smlf 1971709Smlf static struct modlinkage modlinkage = { 1981709Smlf MODREV_1, (void *)&modldrv, NULL 1991709Smlf }; 2001709Smlf 2018863SEdward.Pilatowicz@Sun.COM 2028863SEdward.Pilatowicz@Sun.COM #else /* XPV_HVM_DRIVER */ 2038863SEdward.Pilatowicz@Sun.COM static struct modlmisc modlmisc = { 2048863SEdward.Pilatowicz@Sun.COM &mod_miscops, /* Type of module. This one is a misc */ 2058863SEdward.Pilatowicz@Sun.COM "HVM Common Direct Access Disk", 2068863SEdward.Pilatowicz@Sun.COM }; 2078863SEdward.Pilatowicz@Sun.COM 2088863SEdward.Pilatowicz@Sun.COM static struct modlinkage modlinkage = { 2098863SEdward.Pilatowicz@Sun.COM MODREV_1, (void *)&modlmisc, NULL 2108863SEdward.Pilatowicz@Sun.COM }; 2118863SEdward.Pilatowicz@Sun.COM 2128863SEdward.Pilatowicz@Sun.COM #endif /* XPV_HVM_DRIVER */ 2138863SEdward.Pilatowicz@Sun.COM 2141709Smlf /* Function prototypes for cmlb callbacks */ 2151709Smlf 2161709Smlf static int cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr, 2173525Sshidokht diskaddr_t start, size_t length, void *tg_cookie); 2183525Sshidokht 2193525Sshidokht static int cmdk_lb_getinfo(dev_info_t *dip, int cmd, void *arg, 2203525Sshidokht void *tg_cookie); 2211709Smlf 2221709Smlf static void cmdk_devid_setup(struct cmdk *dkp); 2231709Smlf static int cmdk_devid_modser(struct cmdk *dkp); 2241709Smlf static int cmdk_get_modser(struct cmdk *dkp, int ioccmd, char *buf, int len); 2251709Smlf static int cmdk_devid_fabricate(struct cmdk *dkp); 2261709Smlf static int cmdk_devid_read(struct cmdk *dkp); 2271709Smlf 2281709Smlf static cmlb_tg_ops_t cmdk_lb_ops = { 2293525Sshidokht TG_DK_OPS_VERSION_1, 2301709Smlf cmdk_lb_rdwr, 2313525Sshidokht cmdk_lb_getinfo 2321709Smlf }; 2331709Smlf 2346318Sedp static boolean_t 2356318Sedp cmdk_isopen(struct cmdk *dkp, dev_t dev) 2366318Sedp { 2376318Sedp int part, otyp; 2386318Sedp ulong_t partbit; 2396318Sedp 2406318Sedp ASSERT(MUTEX_HELD((&dkp->dk_mutex))); 2416318Sedp 2426318Sedp part = CMDKPART(dev); 2436318Sedp partbit = 1 << part; 2446318Sedp 2456318Sedp /* account for close */ 2466318Sedp if (dkp->dk_open_lyr[part] != 0) 2476318Sedp return (B_TRUE); 2486318Sedp for (otyp = 0; otyp < OTYPCNT; otyp++) 2496318Sedp if (dkp->dk_open_reg[otyp] & partbit) 2506318Sedp return (B_TRUE); 2516318Sedp return (B_FALSE); 2526318Sedp } 2536318Sedp 2541709Smlf int 2551709Smlf _init(void) 2561709Smlf { 2571709Smlf int rval; 2581709Smlf 2598863SEdward.Pilatowicz@Sun.COM #ifndef XPV_HVM_DRIVER 2601709Smlf if (rval = ddi_soft_state_init(&cmdk_state, sizeof (struct cmdk), 7)) 2611709Smlf return (rval); 2628863SEdward.Pilatowicz@Sun.COM #endif /* !XPV_HVM_DRIVER */ 2631709Smlf 2641709Smlf mutex_init(&cmdk_attach_mutex, NULL, MUTEX_DRIVER, NULL); 2651709Smlf if ((rval = mod_install(&modlinkage)) != 0) { 2661709Smlf mutex_destroy(&cmdk_attach_mutex); 2678863SEdward.Pilatowicz@Sun.COM #ifndef XPV_HVM_DRIVER 2681709Smlf ddi_soft_state_fini(&cmdk_state); 2698863SEdward.Pilatowicz@Sun.COM #endif /* !XPV_HVM_DRIVER */ 2701709Smlf } 2711709Smlf return (rval); 2721709Smlf } 2731709Smlf 2741709Smlf int 2751709Smlf _fini(void) 2761709Smlf { 2771709Smlf return (EBUSY); 2781709Smlf } 2791709Smlf 2801709Smlf int 2811709Smlf _info(struct modinfo *modinfop) 2821709Smlf { 2831709Smlf return (mod_info(&modlinkage, modinfop)); 2841709Smlf } 2851709Smlf 2861709Smlf /* 2871709Smlf * Autoconfiguration Routines 2881709Smlf */ 2891709Smlf static int 2901709Smlf cmdkprobe(dev_info_t *dip) 2911709Smlf { 2921709Smlf int instance; 2931709Smlf int status; 2941709Smlf struct cmdk *dkp; 2951709Smlf 2961709Smlf instance = ddi_get_instance(dip); 2971709Smlf 2988863SEdward.Pilatowicz@Sun.COM #ifndef XPV_HVM_DRIVER 2991709Smlf if (ddi_get_soft_state(cmdk_state, instance)) 3001709Smlf return (DDI_PROBE_PARTIAL); 3011709Smlf 3028863SEdward.Pilatowicz@Sun.COM if (ddi_soft_state_zalloc(cmdk_state, instance) != DDI_SUCCESS) 3038863SEdward.Pilatowicz@Sun.COM return (DDI_PROBE_PARTIAL); 3048863SEdward.Pilatowicz@Sun.COM #endif /* !XPV_HVM_DRIVER */ 3058863SEdward.Pilatowicz@Sun.COM 3068863SEdward.Pilatowicz@Sun.COM if ((dkp = ddi_get_soft_state(cmdk_state, instance)) == NULL) 3071709Smlf return (DDI_PROBE_PARTIAL); 3081709Smlf 3091709Smlf mutex_init(&dkp->dk_mutex, NULL, MUTEX_DRIVER, NULL); 3101709Smlf rw_init(&dkp->dk_bbh_mutex, NULL, RW_DRIVER, NULL); 3111709Smlf dkp->dk_dip = dip; 3121709Smlf mutex_enter(&dkp->dk_mutex); 3131709Smlf 3141709Smlf dkp->dk_dev = makedevice(ddi_driver_major(dip), 3151709Smlf ddi_get_instance(dip) << CMDK_UNITSHF); 3161709Smlf 3171709Smlf /* linkage to dadk and strategy */ 3181709Smlf if (cmdk_create_obj(dip, dkp) != DDI_SUCCESS) { 3191709Smlf mutex_exit(&dkp->dk_mutex); 3201709Smlf mutex_destroy(&dkp->dk_mutex); 3211709Smlf rw_destroy(&dkp->dk_bbh_mutex); 3228863SEdward.Pilatowicz@Sun.COM #ifndef XPV_HVM_DRIVER 3231709Smlf ddi_soft_state_free(cmdk_state, instance); 3248863SEdward.Pilatowicz@Sun.COM #endif /* !XPV_HVM_DRIVER */ 3251709Smlf return (DDI_PROBE_PARTIAL); 3261709Smlf } 3271709Smlf 3281709Smlf status = dadk_probe(DKTP_DATA, KM_NOSLEEP); 3291709Smlf if (status != DDI_PROBE_SUCCESS) { 3301709Smlf cmdk_destroy_obj(dip, dkp); /* dadk/strategy linkage */ 3311709Smlf mutex_exit(&dkp->dk_mutex); 3321709Smlf mutex_destroy(&dkp->dk_mutex); 3331709Smlf rw_destroy(&dkp->dk_bbh_mutex); 3348863SEdward.Pilatowicz@Sun.COM #ifndef XPV_HVM_DRIVER 3351709Smlf ddi_soft_state_free(cmdk_state, instance); 3368863SEdward.Pilatowicz@Sun.COM #endif /* !XPV_HVM_DRIVER */ 3371709Smlf return (status); 3381709Smlf } 3391709Smlf 3401709Smlf mutex_exit(&dkp->dk_mutex); 3411709Smlf #ifdef CMDK_DEBUG 3421709Smlf if (cmdk_debug & DENT) 3431709Smlf PRF("cmdkprobe: instance= %d name= `%s`\n", 3441709Smlf instance, ddi_get_name_addr(dip)); 3451709Smlf #endif 3461709Smlf return (status); 3471709Smlf } 3481709Smlf 3491709Smlf static int 3501709Smlf cmdkattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3511709Smlf { 3521709Smlf int instance; 3531709Smlf struct cmdk *dkp; 3541709Smlf char *node_type; 3551709Smlf 3565295Srandyf switch (cmd) { 3575295Srandyf case DDI_ATTACH: 3585295Srandyf break; 3595295Srandyf case DDI_RESUME: 3605295Srandyf return (cmdkresume(dip)); 3615295Srandyf default: 3621709Smlf return (DDI_FAILURE); 3635295Srandyf } 3641709Smlf 3651709Smlf instance = ddi_get_instance(dip); 3661709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 3671709Smlf return (DDI_FAILURE); 3681709Smlf 3695295Srandyf dkp->dk_pm_level = CMDK_SPINDLE_UNINIT; 3705295Srandyf mutex_init(&dkp->dk_mutex, NULL, MUTEX_DRIVER, NULL); 3715295Srandyf 3721709Smlf mutex_enter(&dkp->dk_mutex); 3731709Smlf 3741709Smlf /* dadk_attach is an empty function that only returns SUCCESS */ 3751709Smlf (void) dadk_attach(DKTP_DATA); 3761709Smlf 3771709Smlf node_type = (DKTP_EXT->tg_nodetype); 3781709Smlf 3791709Smlf /* 3801709Smlf * this open allows cmlb to read the device 3811709Smlf * and determine the label types 3821709Smlf * so that cmlb can create minor nodes for device 3831709Smlf */ 3841709Smlf 3851709Smlf /* open the target disk */ 3861709Smlf if (dadk_open(DKTP_DATA, 0) != DDI_SUCCESS) 3871709Smlf goto fail2; 3881709Smlf 3897563SPrasad.Singamsetty@Sun.COM #ifdef _ILP32 3907563SPrasad.Singamsetty@Sun.COM { 3917563SPrasad.Singamsetty@Sun.COM struct tgdk_geom phyg; 3927563SPrasad.Singamsetty@Sun.COM (void) dadk_getphygeom(DKTP_DATA, &phyg); 3937563SPrasad.Singamsetty@Sun.COM if ((phyg.g_cap - 1) > DK_MAX_BLOCKS) { 3947563SPrasad.Singamsetty@Sun.COM (void) dadk_close(DKTP_DATA); 3957563SPrasad.Singamsetty@Sun.COM goto fail2; 3967563SPrasad.Singamsetty@Sun.COM } 3977563SPrasad.Singamsetty@Sun.COM } 3987563SPrasad.Singamsetty@Sun.COM #endif 3997563SPrasad.Singamsetty@Sun.COM 4007563SPrasad.Singamsetty@Sun.COM 4011709Smlf /* mark as having opened target */ 4021709Smlf dkp->dk_flag |= CMDK_TGDK_OPEN; 4031709Smlf 4041709Smlf cmlb_alloc_handle((cmlb_handle_t *)&dkp->dk_cmlbhandle); 4051709Smlf 4061709Smlf if (cmlb_attach(dip, 4071709Smlf &cmdk_lb_ops, 4081709Smlf DTYPE_DIRECT, /* device_type */ 4098863SEdward.Pilatowicz@Sun.COM B_FALSE, /* removable */ 4108863SEdward.Pilatowicz@Sun.COM B_FALSE, /* hot pluggable XXX */ 4111709Smlf node_type, 4121709Smlf CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT, /* alter_behaviour */ 4133525Sshidokht dkp->dk_cmlbhandle, 4143525Sshidokht 0) != 0) 4151709Smlf goto fail1; 4161709Smlf 4171709Smlf /* Calling validate will create minor nodes according to disk label */ 4183525Sshidokht (void) cmlb_validate(dkp->dk_cmlbhandle, 0, 0); 4191709Smlf 4201709Smlf /* set bbh (Bad Block Handling) */ 4211709Smlf cmdk_bbh_reopen(dkp); 4221709Smlf 4231709Smlf /* setup devid string */ 4241709Smlf cmdk_devid_setup(dkp); 4251709Smlf 4261709Smlf mutex_enter(&cmdk_attach_mutex); 4271709Smlf if (instance > cmdk_max_instance) 4281709Smlf cmdk_max_instance = instance; 4291709Smlf mutex_exit(&cmdk_attach_mutex); 4301709Smlf 4311709Smlf mutex_exit(&dkp->dk_mutex); 4321709Smlf 4331709Smlf /* 4341709Smlf * Add a zero-length attribute to tell the world we support 4351709Smlf * kernel ioctls (for layered drivers) 4361709Smlf */ 4371709Smlf (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 4381709Smlf DDI_KERNEL_IOCTL, NULL, 0); 4391709Smlf ddi_report_dev(dip); 4401709Smlf 4415295Srandyf /* 4425295Srandyf * Initialize power management 4435295Srandyf */ 4445295Srandyf mutex_init(&dkp->dk_pm_mutex, NULL, MUTEX_DRIVER, NULL); 4455295Srandyf cv_init(&dkp->dk_suspend_cv, NULL, CV_DRIVER, NULL); 4465295Srandyf cmdk_setup_pm(dip, dkp); 4475295Srandyf 4481709Smlf return (DDI_SUCCESS); 4491709Smlf 4501709Smlf fail1: 4511709Smlf cmlb_free_handle(&dkp->dk_cmlbhandle); 4521709Smlf (void) dadk_close(DKTP_DATA); 4531709Smlf fail2: 4541709Smlf cmdk_destroy_obj(dip, dkp); 4551709Smlf rw_destroy(&dkp->dk_bbh_mutex); 4561709Smlf mutex_exit(&dkp->dk_mutex); 4571709Smlf mutex_destroy(&dkp->dk_mutex); 4588863SEdward.Pilatowicz@Sun.COM #ifndef XPV_HVM_DRIVER 4591709Smlf ddi_soft_state_free(cmdk_state, instance); 4608863SEdward.Pilatowicz@Sun.COM #endif /* !XPV_HVM_DRIVER */ 4611709Smlf return (DDI_FAILURE); 4621709Smlf } 4631709Smlf 4641709Smlf 4651709Smlf static int 4661709Smlf cmdkdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4671709Smlf { 4681709Smlf struct cmdk *dkp; 4691709Smlf int instance; 4701709Smlf int max_instance; 4711709Smlf 4725295Srandyf switch (cmd) { 4735295Srandyf case DDI_DETACH: 4745295Srandyf /* return (DDI_FAILURE); */ 4755295Srandyf break; 4765295Srandyf case DDI_SUSPEND: 4775295Srandyf return (cmdksuspend(dip)); 4785295Srandyf default: 4791709Smlf #ifdef CMDK_DEBUG 4801709Smlf if (cmdk_debug & DIO) { 4811709Smlf PRF("cmdkdetach: cmd = %d unknown\n", cmd); 4821709Smlf } 4831709Smlf #endif 4841709Smlf return (DDI_FAILURE); 4851709Smlf } 4861709Smlf 4871709Smlf mutex_enter(&cmdk_attach_mutex); 4881709Smlf max_instance = cmdk_max_instance; 4891709Smlf mutex_exit(&cmdk_attach_mutex); 4901709Smlf 4911709Smlf /* check if any instance of driver is open */ 4921709Smlf for (instance = 0; instance < max_instance; instance++) { 4931709Smlf dkp = ddi_get_soft_state(cmdk_state, instance); 4941709Smlf if (!dkp) 4951709Smlf continue; 4961709Smlf if (dkp->dk_flag & CMDK_OPEN) 4971709Smlf return (DDI_FAILURE); 4981709Smlf } 4991709Smlf 5001709Smlf instance = ddi_get_instance(dip); 5011709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 5021709Smlf return (DDI_SUCCESS); 5031709Smlf 5041709Smlf mutex_enter(&dkp->dk_mutex); 5051709Smlf 5061709Smlf /* 5071709Smlf * The cmdk_part_info call at the end of cmdkattach may have 5081709Smlf * caused cmdk_reopen to do a TGDK_OPEN, make sure we close on 5091709Smlf * detach for case when cmdkopen/cmdkclose never occurs. 5101709Smlf */ 5111709Smlf if (dkp->dk_flag & CMDK_TGDK_OPEN) { 5121709Smlf dkp->dk_flag &= ~CMDK_TGDK_OPEN; 5131709Smlf (void) dadk_close(DKTP_DATA); 5141709Smlf } 5151709Smlf 5163525Sshidokht cmlb_detach(dkp->dk_cmlbhandle, 0); 5171709Smlf cmlb_free_handle(&dkp->dk_cmlbhandle); 5181709Smlf ddi_prop_remove_all(dip); 5191709Smlf 5201709Smlf cmdk_destroy_obj(dip, dkp); /* dadk/strategy linkage */ 5211709Smlf mutex_exit(&dkp->dk_mutex); 5221709Smlf mutex_destroy(&dkp->dk_mutex); 5231709Smlf rw_destroy(&dkp->dk_bbh_mutex); 5245295Srandyf mutex_destroy(&dkp->dk_pm_mutex); 5255295Srandyf cv_destroy(&dkp->dk_suspend_cv); 5268863SEdward.Pilatowicz@Sun.COM #ifndef XPV_HVM_DRIVER 5271709Smlf ddi_soft_state_free(cmdk_state, instance); 5288863SEdward.Pilatowicz@Sun.COM #endif /* !XPV_HVM_DRIVER */ 5291709Smlf 5301709Smlf return (DDI_SUCCESS); 5311709Smlf } 5321709Smlf 5331709Smlf static int 5341709Smlf cmdkinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 5351709Smlf { 5361709Smlf dev_t dev = (dev_t)arg; 5371709Smlf int instance; 5381709Smlf struct cmdk *dkp; 5391709Smlf 5401709Smlf #ifdef lint 5411709Smlf dip = dip; /* no one ever uses this */ 5421709Smlf #endif 5431709Smlf #ifdef CMDK_DEBUG 5441709Smlf if (cmdk_debug & DENT) 5451709Smlf PRF("cmdkinfo: call\n"); 5461709Smlf #endif 5471709Smlf instance = CMDKUNIT(dev); 5481709Smlf 5491709Smlf switch (infocmd) { 5501709Smlf case DDI_INFO_DEVT2DEVINFO: 5511709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 5521709Smlf return (DDI_FAILURE); 5531709Smlf *result = (void *) dkp->dk_dip; 5541709Smlf break; 5551709Smlf case DDI_INFO_DEVT2INSTANCE: 5561709Smlf *result = (void *)(intptr_t)instance; 5571709Smlf break; 5581709Smlf default: 5591709Smlf return (DDI_FAILURE); 5601709Smlf } 5611709Smlf return (DDI_SUCCESS); 5621709Smlf } 5631709Smlf 5645295Srandyf /* 5655295Srandyf * Initialize the power management components 5665295Srandyf */ 5675295Srandyf static void 5685295Srandyf cmdk_setup_pm(dev_info_t *dip, struct cmdk *dkp) 5695295Srandyf { 5705295Srandyf char *pm_comp[] = { "NAME=cmdk", "0=off", "1=on", NULL }; 5715295Srandyf 5725295Srandyf /* 5735295Srandyf * Since the cmdk device does not the 'reg' property, 5745295Srandyf * cpr will not call its DDI_SUSPEND/DDI_RESUME entries. 5755295Srandyf * The following code is to tell cpr that this device 5765295Srandyf * DOES need to be suspended and resumed. 5775295Srandyf */ 5785295Srandyf (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, 5795295Srandyf "pm-hardware-state", "needs-suspend-resume"); 5805295Srandyf 5815295Srandyf if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip, 5825295Srandyf "pm-components", pm_comp, 3) == DDI_PROP_SUCCESS) { 5835295Srandyf if (pm_raise_power(dip, 0, CMDK_SPINDLE_ON) == DDI_SUCCESS) { 5845295Srandyf mutex_enter(&dkp->dk_pm_mutex); 5855295Srandyf dkp->dk_pm_level = CMDK_SPINDLE_ON; 5865295Srandyf dkp->dk_pm_is_enabled = 1; 5875295Srandyf mutex_exit(&dkp->dk_pm_mutex); 5885295Srandyf } else { 5895295Srandyf mutex_enter(&dkp->dk_pm_mutex); 5905295Srandyf dkp->dk_pm_level = CMDK_SPINDLE_OFF; 5915295Srandyf dkp->dk_pm_is_enabled = 0; 5925295Srandyf mutex_exit(&dkp->dk_pm_mutex); 5935295Srandyf } 5945295Srandyf } else { 5955295Srandyf mutex_enter(&dkp->dk_pm_mutex); 5965295Srandyf dkp->dk_pm_level = CMDK_SPINDLE_UNINIT; 5975295Srandyf dkp->dk_pm_is_enabled = 0; 5985295Srandyf mutex_exit(&dkp->dk_pm_mutex); 5995295Srandyf } 6005295Srandyf } 6015295Srandyf 6025295Srandyf /* 6035295Srandyf * suspend routine, it will be run when get the command 6045295Srandyf * DDI_SUSPEND at detach(9E) from system power management 6055295Srandyf */ 6065295Srandyf static int 6075295Srandyf cmdksuspend(dev_info_t *dip) 6085295Srandyf { 6095295Srandyf struct cmdk *dkp; 6105295Srandyf int instance; 6115295Srandyf clock_t count = 0; 6125295Srandyf 6135295Srandyf instance = ddi_get_instance(dip); 6145295Srandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 6155295Srandyf return (DDI_FAILURE); 6165295Srandyf mutex_enter(&dkp->dk_mutex); 6175295Srandyf if (dkp->dk_flag & CMDK_SUSPEND) { 6185295Srandyf mutex_exit(&dkp->dk_mutex); 6195295Srandyf return (DDI_SUCCESS); 6205295Srandyf } 6215295Srandyf dkp->dk_flag |= CMDK_SUSPEND; 6225295Srandyf 6235295Srandyf /* need to wait a while */ 6245295Srandyf while (dadk_getcmds(DKTP_DATA) != 0) { 6255295Srandyf delay(drv_usectohz(1000000)); 6265295Srandyf if (count > 60) { 6275295Srandyf dkp->dk_flag &= ~CMDK_SUSPEND; 6285295Srandyf cv_broadcast(&dkp->dk_suspend_cv); 6295295Srandyf mutex_exit(&dkp->dk_mutex); 6305295Srandyf return (DDI_FAILURE); 6315295Srandyf } 6325295Srandyf count++; 6335295Srandyf } 6345295Srandyf mutex_exit(&dkp->dk_mutex); 6355295Srandyf return (DDI_SUCCESS); 6365295Srandyf } 6375295Srandyf 6385295Srandyf /* 6395295Srandyf * resume routine, it will be run when get the command 6405295Srandyf * DDI_RESUME at attach(9E) from system power management 6415295Srandyf */ 6425295Srandyf static int 6435295Srandyf cmdkresume(dev_info_t *dip) 6445295Srandyf { 6455295Srandyf struct cmdk *dkp; 6465295Srandyf int instance; 6475295Srandyf 6485295Srandyf instance = ddi_get_instance(dip); 6495295Srandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 6505295Srandyf return (DDI_FAILURE); 6515295Srandyf mutex_enter(&dkp->dk_mutex); 6525295Srandyf if (!(dkp->dk_flag & CMDK_SUSPEND)) { 6535295Srandyf mutex_exit(&dkp->dk_mutex); 6545295Srandyf return (DDI_FAILURE); 6555295Srandyf } 6565295Srandyf dkp->dk_pm_level = CMDK_SPINDLE_ON; 6575295Srandyf dkp->dk_flag &= ~CMDK_SUSPEND; 6585295Srandyf cv_broadcast(&dkp->dk_suspend_cv); 6595295Srandyf mutex_exit(&dkp->dk_mutex); 6605295Srandyf return (DDI_SUCCESS); 6615295Srandyf 6625295Srandyf } 6635295Srandyf 6645295Srandyf /* 6655295Srandyf * power management entry point, it was used to 6665295Srandyf * change power management component. 6675295Srandyf * Actually, the real hard drive suspend/resume 6685295Srandyf * was handled in ata, so this function is not 6695295Srandyf * doing any real work other than verifying that 6705295Srandyf * the disk is idle. 6715295Srandyf */ 6725295Srandyf static int 6735295Srandyf cmdkpower(dev_info_t *dip, int component, int level) 6745295Srandyf { 6755295Srandyf struct cmdk *dkp; 6765295Srandyf int instance; 6775295Srandyf 6785295Srandyf instance = ddi_get_instance(dip); 6795295Srandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) || 6805295Srandyf component != 0 || level > CMDK_SPINDLE_ON || 6815295Srandyf level < CMDK_SPINDLE_OFF) { 6825295Srandyf return (DDI_FAILURE); 6835295Srandyf } 6845295Srandyf 6855295Srandyf mutex_enter(&dkp->dk_pm_mutex); 6865295Srandyf if (dkp->dk_pm_is_enabled && dkp->dk_pm_level == level) { 6875295Srandyf mutex_exit(&dkp->dk_pm_mutex); 6885295Srandyf return (DDI_SUCCESS); 6895295Srandyf } 6905295Srandyf mutex_exit(&dkp->dk_pm_mutex); 6915295Srandyf 6925295Srandyf if ((level == CMDK_SPINDLE_OFF) && 6935295Srandyf (dadk_getcmds(DKTP_DATA) != 0)) { 6945295Srandyf return (DDI_FAILURE); 6955295Srandyf } 6965295Srandyf 6975295Srandyf mutex_enter(&dkp->dk_pm_mutex); 6985295Srandyf dkp->dk_pm_level = level; 6995295Srandyf mutex_exit(&dkp->dk_pm_mutex); 7005295Srandyf return (DDI_SUCCESS); 7015295Srandyf } 7025295Srandyf 7031709Smlf static int 7041709Smlf cmdk_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags, 7051709Smlf char *name, caddr_t valuep, int *lengthp) 7061709Smlf { 7071709Smlf struct cmdk *dkp; 7081709Smlf 7091709Smlf #ifdef CMDK_DEBUG 7101709Smlf if (cmdk_debug & DENT) 7111709Smlf PRF("cmdk_prop_op: call\n"); 7121709Smlf #endif 7131709Smlf 7141709Smlf dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip)); 7157224Scth if (dkp == NULL) 7167224Scth return (ddi_prop_op(dev, dip, prop_op, mod_flags, 7177224Scth name, valuep, lengthp)); 7181709Smlf 7197224Scth return (cmlb_prop_op(dkp->dk_cmlbhandle, 7207224Scth dev, dip, prop_op, mod_flags, name, valuep, lengthp, 7217224Scth CMDKPART(dev), NULL)); 7221709Smlf } 7231709Smlf 7241709Smlf /* 7251709Smlf * dump routine 7261709Smlf */ 7271709Smlf static int 7281709Smlf cmdkdump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk) 7291709Smlf { 7301709Smlf int instance; 7311709Smlf struct cmdk *dkp; 7321709Smlf diskaddr_t p_lblksrt; 7331709Smlf diskaddr_t p_lblkcnt; 7341709Smlf struct buf local; 7351709Smlf struct buf *bp; 7361709Smlf 7371709Smlf #ifdef CMDK_DEBUG 7381709Smlf if (cmdk_debug & DENT) 7391709Smlf PRF("cmdkdump: call\n"); 7401709Smlf #endif 7411709Smlf instance = CMDKUNIT(dev); 7421709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) || (blkno < 0)) 7431709Smlf return (ENXIO); 7441709Smlf 7451709Smlf if (cmlb_partinfo( 7461709Smlf dkp->dk_cmlbhandle, 7471709Smlf CMDKPART(dev), 7481709Smlf &p_lblkcnt, 7491709Smlf &p_lblksrt, 7501709Smlf NULL, 7513525Sshidokht NULL, 7523525Sshidokht 0)) { 7531709Smlf return (ENXIO); 7541709Smlf } 7551709Smlf 7561709Smlf if ((blkno+nblk) > p_lblkcnt) 7571709Smlf return (EINVAL); 7581709Smlf 7591709Smlf cmdk_indump = 1; /* Tell disk targets we are panic dumpping */ 7601709Smlf 7611709Smlf bp = &local; 7621709Smlf bzero(bp, sizeof (*bp)); 7631709Smlf bp->b_flags = B_BUSY; 7641709Smlf bp->b_un.b_addr = addr; 7651709Smlf bp->b_bcount = nblk << SCTRSHFT; 7661709Smlf SET_BP_SEC(bp, ((ulong_t)(p_lblksrt + blkno))); 7671709Smlf 7681709Smlf (void) dadk_dump(DKTP_DATA, bp); 7691709Smlf return (bp->b_error); 7701709Smlf } 7711709Smlf 7721709Smlf /* 7731709Smlf * Copy in the dadkio_rwcmd according to the user's data model. If needed, 7741709Smlf * convert it for our internal use. 7751709Smlf */ 7761709Smlf static int 7771709Smlf rwcmd_copyin(struct dadkio_rwcmd *rwcmdp, caddr_t inaddr, int flag) 7781709Smlf { 7791709Smlf switch (ddi_model_convert_from(flag)) { 7801709Smlf case DDI_MODEL_ILP32: { 7811709Smlf struct dadkio_rwcmd32 cmd32; 7821709Smlf 7831709Smlf if (ddi_copyin(inaddr, &cmd32, 7841709Smlf sizeof (struct dadkio_rwcmd32), flag)) { 7851709Smlf return (EFAULT); 7861709Smlf } 7871709Smlf 7881709Smlf rwcmdp->cmd = cmd32.cmd; 7891709Smlf rwcmdp->flags = cmd32.flags; 7907563SPrasad.Singamsetty@Sun.COM rwcmdp->blkaddr = (blkaddr_t)cmd32.blkaddr; 7911709Smlf rwcmdp->buflen = cmd32.buflen; 7921709Smlf rwcmdp->bufaddr = (caddr_t)(intptr_t)cmd32.bufaddr; 7931709Smlf /* 7941709Smlf * Note: we do not convert the 'status' field, 7951709Smlf * as it should not contain valid data at this 7961709Smlf * point. 7971709Smlf */ 7981709Smlf bzero(&rwcmdp->status, sizeof (rwcmdp->status)); 7991709Smlf break; 8001709Smlf } 8011709Smlf case DDI_MODEL_NONE: { 8021709Smlf if (ddi_copyin(inaddr, rwcmdp, 8031709Smlf sizeof (struct dadkio_rwcmd), flag)) { 8041709Smlf return (EFAULT); 8051709Smlf } 8061709Smlf } 8071709Smlf } 8081709Smlf return (0); 8091709Smlf } 8101709Smlf 8111709Smlf /* 8121709Smlf * If necessary, convert the internal rwcmdp and status to the appropriate 8131709Smlf * data model and copy it out to the user. 8141709Smlf */ 8151709Smlf static int 8161709Smlf rwcmd_copyout(struct dadkio_rwcmd *rwcmdp, caddr_t outaddr, int flag) 8171709Smlf { 8181709Smlf switch (ddi_model_convert_from(flag)) { 8191709Smlf case DDI_MODEL_ILP32: { 8201709Smlf struct dadkio_rwcmd32 cmd32; 8211709Smlf 8221709Smlf cmd32.cmd = rwcmdp->cmd; 8231709Smlf cmd32.flags = rwcmdp->flags; 8241709Smlf cmd32.blkaddr = rwcmdp->blkaddr; 8251709Smlf cmd32.buflen = rwcmdp->buflen; 8261709Smlf ASSERT64(((uintptr_t)rwcmdp->bufaddr >> 32) == 0); 8271709Smlf cmd32.bufaddr = (caddr32_t)(uintptr_t)rwcmdp->bufaddr; 8281709Smlf 8291709Smlf cmd32.status.status = rwcmdp->status.status; 8301709Smlf cmd32.status.resid = rwcmdp->status.resid; 8311709Smlf cmd32.status.failed_blk_is_valid = 8321709Smlf rwcmdp->status.failed_blk_is_valid; 8331709Smlf cmd32.status.failed_blk = rwcmdp->status.failed_blk; 8341709Smlf cmd32.status.fru_code_is_valid = 8351709Smlf rwcmdp->status.fru_code_is_valid; 8361709Smlf cmd32.status.fru_code = rwcmdp->status.fru_code; 8371709Smlf 8381709Smlf bcopy(rwcmdp->status.add_error_info, 8391709Smlf cmd32.status.add_error_info, DADKIO_ERROR_INFO_LEN); 8401709Smlf 8411709Smlf if (ddi_copyout(&cmd32, outaddr, 8421709Smlf sizeof (struct dadkio_rwcmd32), flag)) 8431709Smlf return (EFAULT); 8441709Smlf break; 8451709Smlf } 8461709Smlf case DDI_MODEL_NONE: { 8471709Smlf if (ddi_copyout(rwcmdp, outaddr, 8481709Smlf sizeof (struct dadkio_rwcmd), flag)) 8491709Smlf return (EFAULT); 8501709Smlf } 8511709Smlf } 8521709Smlf return (0); 8531709Smlf } 8541709Smlf 8551709Smlf /* 8561709Smlf * ioctl routine 8571709Smlf */ 8581709Smlf static int 8591709Smlf cmdkioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp) 8601709Smlf { 8611709Smlf int instance; 8621709Smlf struct scsi_device *devp; 8631709Smlf struct cmdk *dkp; 8641709Smlf char data[NBPSCTR]; 8651709Smlf 8661709Smlf instance = CMDKUNIT(dev); 8671709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 8681709Smlf return (ENXIO); 8691709Smlf 8705295Srandyf mutex_enter(&dkp->dk_mutex); 8715295Srandyf while (dkp->dk_flag & CMDK_SUSPEND) { 8725295Srandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 8735295Srandyf } 8745295Srandyf mutex_exit(&dkp->dk_mutex); 8755295Srandyf 8761709Smlf bzero(data, sizeof (data)); 8771709Smlf 8781709Smlf switch (cmd) { 8791709Smlf 8801709Smlf case DKIOCGMEDIAINFO: { 8811709Smlf struct dk_minfo media_info; 8821709Smlf struct tgdk_geom phyg; 8831709Smlf 8841709Smlf /* dadk_getphygeom always returns success */ 8851709Smlf (void) dadk_getphygeom(DKTP_DATA, &phyg); 8861709Smlf 8871709Smlf media_info.dki_lbsize = phyg.g_secsiz; 8881709Smlf media_info.dki_capacity = phyg.g_cap; 8891709Smlf media_info.dki_media_type = DK_FIXED_DISK; 8901709Smlf 8911709Smlf if (ddi_copyout(&media_info, (void *)arg, 8921709Smlf sizeof (struct dk_minfo), flag)) { 8931709Smlf return (EFAULT); 8941709Smlf } else { 8951709Smlf return (0); 8961709Smlf } 8971709Smlf } 8981709Smlf 8991709Smlf case DKIOCINFO: { 9001709Smlf struct dk_cinfo *info = (struct dk_cinfo *)data; 9011709Smlf 9021709Smlf /* controller information */ 9031709Smlf info->dki_ctype = (DKTP_EXT->tg_ctype); 9041709Smlf info->dki_cnum = ddi_get_instance(ddi_get_parent(dkp->dk_dip)); 9051709Smlf (void) strcpy(info->dki_cname, 9061709Smlf ddi_get_name(ddi_get_parent(dkp->dk_dip))); 9071709Smlf 9081709Smlf /* Unit Information */ 9091709Smlf info->dki_unit = ddi_get_instance(dkp->dk_dip); 9101709Smlf devp = ddi_get_driver_private(dkp->dk_dip); 9111709Smlf info->dki_slave = (CMDEV_TARG(devp)<<3) | CMDEV_LUN(devp); 9121709Smlf (void) strcpy(info->dki_dname, ddi_driver_name(dkp->dk_dip)); 9131709Smlf info->dki_flags = DKI_FMTVOL; 9141709Smlf info->dki_partition = CMDKPART(dev); 9151709Smlf 9161709Smlf info->dki_maxtransfer = maxphys / DEV_BSIZE; 9171709Smlf info->dki_addr = 1; 9181709Smlf info->dki_space = 0; 9191709Smlf info->dki_prio = 0; 9201709Smlf info->dki_vec = 0; 9211709Smlf 9221709Smlf if (ddi_copyout(data, (void *)arg, sizeof (*info), flag)) 9231709Smlf return (EFAULT); 9241709Smlf else 9251709Smlf return (0); 9261709Smlf } 9271709Smlf 9281709Smlf case DKIOCSTATE: { 9291709Smlf int state; 9301709Smlf int rval; 9311709Smlf diskaddr_t p_lblksrt; 9321709Smlf diskaddr_t p_lblkcnt; 9331709Smlf 9341709Smlf if (ddi_copyin((void *)arg, &state, sizeof (int), flag)) 9351709Smlf return (EFAULT); 9361709Smlf 9371709Smlf /* dadk_check_media blocks until state changes */ 9381709Smlf if (rval = dadk_check_media(DKTP_DATA, &state)) 9391709Smlf return (rval); 9401709Smlf 9411709Smlf if (state == DKIO_INSERTED) { 9421709Smlf 9433525Sshidokht if (cmlb_validate(dkp->dk_cmlbhandle, 0, 0) != 0) 9441709Smlf return (ENXIO); 9451709Smlf 9461709Smlf if (cmlb_partinfo(dkp->dk_cmlbhandle, CMDKPART(dev), 9473525Sshidokht &p_lblkcnt, &p_lblksrt, NULL, NULL, 0)) 9481709Smlf return (ENXIO); 9491709Smlf 9501709Smlf if (p_lblkcnt <= 0) 9511709Smlf return (ENXIO); 9521709Smlf } 9531709Smlf 9541709Smlf if (ddi_copyout(&state, (caddr_t)arg, sizeof (int), flag)) 9551709Smlf return (EFAULT); 9561709Smlf 9571709Smlf return (0); 9581709Smlf } 9591709Smlf 9601709Smlf /* 9611709Smlf * is media removable? 9621709Smlf */ 9631709Smlf case DKIOCREMOVABLE: { 9641709Smlf int i; 9651709Smlf 9661709Smlf i = (DKTP_EXT->tg_rmb) ? 1 : 0; 9671709Smlf 9681709Smlf if (ddi_copyout(&i, (caddr_t)arg, sizeof (int), flag)) 9691709Smlf return (EFAULT); 9701709Smlf 9711709Smlf return (0); 9721709Smlf } 9731709Smlf 9741709Smlf case DKIOCADDBAD: 9751709Smlf /* 9761709Smlf * This is not an update mechanism to add bad blocks 9771709Smlf * to the bad block structures stored on disk. 9781709Smlf * 9791709Smlf * addbadsec(1M) will update the bad block data on disk 9801709Smlf * and use this ioctl to force the driver to re-initialize 9811709Smlf * the list of bad blocks in the driver. 9821709Smlf */ 9831709Smlf 9841709Smlf /* start BBH */ 9851709Smlf cmdk_bbh_reopen(dkp); 9861709Smlf return (0); 9871709Smlf 9881709Smlf case DKIOCG_PHYGEOM: 9891709Smlf case DKIOCG_VIRTGEOM: 9901709Smlf case DKIOCGGEOM: 9911709Smlf case DKIOCSGEOM: 9921709Smlf case DKIOCGAPART: 9931709Smlf case DKIOCSAPART: 9941709Smlf case DKIOCGVTOC: 9951709Smlf case DKIOCSVTOC: 9961709Smlf case DKIOCPARTINFO: 9977563SPrasad.Singamsetty@Sun.COM case DKIOCGEXTVTOC: 9987563SPrasad.Singamsetty@Sun.COM case DKIOCSEXTVTOC: 9997563SPrasad.Singamsetty@Sun.COM case DKIOCEXTPARTINFO: 10001709Smlf case DKIOCGMBOOT: 10011709Smlf case DKIOCSMBOOT: 10021709Smlf case DKIOCGETEFI: 10031709Smlf case DKIOCSETEFI: 10041709Smlf case DKIOCPARTITION: 100510021SSheshadri.Vasudevan@Sun.COM case DKIOCSETEXTPART: 10061709Smlf { 10071709Smlf int rc; 10081709Smlf 10093525Sshidokht rc = cmlb_ioctl(dkp->dk_cmlbhandle, dev, cmd, arg, flag, 10103525Sshidokht credp, rvalp, 0); 10118124SJan.Setje-Eilers@Sun.COM if (cmd == DKIOCSVTOC || cmd == DKIOCSEXTVTOC) 10121709Smlf cmdk_devid_setup(dkp); 10131709Smlf return (rc); 10141709Smlf } 10151709Smlf 10161709Smlf case DIOCTL_RWCMD: { 10171709Smlf struct dadkio_rwcmd *rwcmdp; 10181709Smlf int status; 10191709Smlf 10201709Smlf rwcmdp = kmem_alloc(sizeof (struct dadkio_rwcmd), KM_SLEEP); 10211709Smlf 10221709Smlf status = rwcmd_copyin(rwcmdp, (caddr_t)arg, flag); 10231709Smlf 10241709Smlf if (status == 0) { 10251709Smlf bzero(&(rwcmdp->status), sizeof (struct dadkio_status)); 10261709Smlf status = dadk_ioctl(DKTP_DATA, 10271709Smlf dev, 10281709Smlf cmd, 10291709Smlf (uintptr_t)rwcmdp, 10301709Smlf flag, 10311709Smlf credp, 10321709Smlf rvalp); 10331709Smlf } 10341709Smlf if (status == 0) 10351709Smlf status = rwcmd_copyout(rwcmdp, (caddr_t)arg, flag); 10361709Smlf 10371709Smlf kmem_free(rwcmdp, sizeof (struct dadkio_rwcmd)); 10381709Smlf return (status); 10391709Smlf } 10401709Smlf 10411709Smlf default: 10421709Smlf return (dadk_ioctl(DKTP_DATA, 10431709Smlf dev, 10441709Smlf cmd, 10451709Smlf arg, 10461709Smlf flag, 10471709Smlf credp, 10481709Smlf rvalp)); 10491709Smlf } 10501709Smlf } 10511709Smlf 10521709Smlf /*ARGSUSED1*/ 10531709Smlf static int 10541709Smlf cmdkclose(dev_t dev, int flag, int otyp, cred_t *credp) 10551709Smlf { 10561709Smlf int part; 10571709Smlf ulong_t partbit; 10581709Smlf int instance; 10591709Smlf struct cmdk *dkp; 10601709Smlf int lastclose = 1; 10611709Smlf int i; 10621709Smlf 10631709Smlf instance = CMDKUNIT(dev); 10641709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) || 10651709Smlf (otyp >= OTYPCNT)) 10661709Smlf return (ENXIO); 10671709Smlf 10681709Smlf mutex_enter(&dkp->dk_mutex); 10691709Smlf 10701709Smlf /* check if device has been opened */ 10716318Sedp ASSERT(cmdk_isopen(dkp, dev)); 10721709Smlf if (!(dkp->dk_flag & CMDK_OPEN)) { 10731709Smlf mutex_exit(&dkp->dk_mutex); 10741709Smlf return (ENXIO); 10751709Smlf } 10761709Smlf 10775295Srandyf while (dkp->dk_flag & CMDK_SUSPEND) { 10785295Srandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 10795295Srandyf } 10805295Srandyf 10811709Smlf part = CMDKPART(dev); 10821709Smlf partbit = 1 << part; 10831709Smlf 10841709Smlf /* account for close */ 10851709Smlf if (otyp == OTYP_LYR) { 10866318Sedp ASSERT(dkp->dk_open_lyr[part] > 0); 10871709Smlf if (dkp->dk_open_lyr[part]) 10881709Smlf dkp->dk_open_lyr[part]--; 10896318Sedp } else { 10906318Sedp ASSERT((dkp->dk_open_reg[otyp] & partbit) != 0); 10911709Smlf dkp->dk_open_reg[otyp] &= ~partbit; 10926318Sedp } 10931709Smlf dkp->dk_open_exl &= ~partbit; 10941709Smlf 10951709Smlf for (i = 0; i < CMDK_MAXPART; i++) 10961709Smlf if (dkp->dk_open_lyr[i] != 0) { 10971709Smlf lastclose = 0; 10981709Smlf break; 10991709Smlf } 11001709Smlf 11011709Smlf if (lastclose) 11021709Smlf for (i = 0; i < OTYPCNT; i++) 11031709Smlf if (dkp->dk_open_reg[i] != 0) { 11041709Smlf lastclose = 0; 11051709Smlf break; 11061709Smlf } 11071709Smlf 11081709Smlf mutex_exit(&dkp->dk_mutex); 11091709Smlf 11101709Smlf if (lastclose) 11113525Sshidokht cmlb_invalidate(dkp->dk_cmlbhandle, 0); 11121709Smlf 11131709Smlf return (DDI_SUCCESS); 11141709Smlf } 11151709Smlf 11161709Smlf /*ARGSUSED3*/ 11171709Smlf static int 11181709Smlf cmdkopen(dev_t *dev_p, int flag, int otyp, cred_t *credp) 11191709Smlf { 11201709Smlf dev_t dev = *dev_p; 11211709Smlf int part; 11221709Smlf ulong_t partbit; 11231709Smlf int instance; 11241709Smlf struct cmdk *dkp; 11251709Smlf diskaddr_t p_lblksrt; 11261709Smlf diskaddr_t p_lblkcnt; 11271709Smlf int i; 11281709Smlf int nodelay; 11291709Smlf 11301709Smlf instance = CMDKUNIT(dev); 11311709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 11321709Smlf return (ENXIO); 11331709Smlf 11341709Smlf if (otyp >= OTYPCNT) 11351709Smlf return (EINVAL); 11361709Smlf 11375295Srandyf mutex_enter(&dkp->dk_mutex); 11385295Srandyf while (dkp->dk_flag & CMDK_SUSPEND) { 11395295Srandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 11405295Srandyf } 11415295Srandyf mutex_exit(&dkp->dk_mutex); 11425295Srandyf 11431709Smlf part = CMDKPART(dev); 11441709Smlf partbit = 1 << part; 11451709Smlf nodelay = (flag & (FNDELAY | FNONBLOCK)); 11461709Smlf 11471709Smlf mutex_enter(&dkp->dk_mutex); 11481709Smlf 11493525Sshidokht if (cmlb_validate(dkp->dk_cmlbhandle, 0, 0) != 0) { 11501709Smlf 11511709Smlf /* fail if not doing non block open */ 11521709Smlf if (!nodelay) { 11531709Smlf mutex_exit(&dkp->dk_mutex); 11541709Smlf return (ENXIO); 11551709Smlf } 11561709Smlf } else if (cmlb_partinfo(dkp->dk_cmlbhandle, part, &p_lblkcnt, 11573525Sshidokht &p_lblksrt, NULL, NULL, 0) == 0) { 11581709Smlf 11591709Smlf if (p_lblkcnt <= 0 && (!nodelay || otyp != OTYP_CHR)) { 11601709Smlf mutex_exit(&dkp->dk_mutex); 11611709Smlf return (ENXIO); 11621709Smlf } 11631709Smlf } else { 11641709Smlf /* fail if not doing non block open */ 11651709Smlf if (!nodelay) { 11661709Smlf mutex_exit(&dkp->dk_mutex); 11671709Smlf return (ENXIO); 11681709Smlf } 11691709Smlf } 11701709Smlf 11711709Smlf if ((DKTP_EXT->tg_rdonly) && (flag & FWRITE)) { 11721709Smlf mutex_exit(&dkp->dk_mutex); 11731709Smlf return (EROFS); 11741709Smlf } 11751709Smlf 11761709Smlf /* check for part already opend exclusively */ 11771709Smlf if (dkp->dk_open_exl & partbit) 11781709Smlf goto excl_open_fail; 11791709Smlf 11801709Smlf /* check if we can establish exclusive open */ 11811709Smlf if (flag & FEXCL) { 11821709Smlf if (dkp->dk_open_lyr[part]) 11831709Smlf goto excl_open_fail; 11841709Smlf for (i = 0; i < OTYPCNT; i++) { 11851709Smlf if (dkp->dk_open_reg[i] & partbit) 11861709Smlf goto excl_open_fail; 11871709Smlf } 11881709Smlf } 11891709Smlf 11901709Smlf /* open will succeed, account for open */ 11911709Smlf dkp->dk_flag |= CMDK_OPEN; 11921709Smlf if (otyp == OTYP_LYR) 11931709Smlf dkp->dk_open_lyr[part]++; 11941709Smlf else 11951709Smlf dkp->dk_open_reg[otyp] |= partbit; 11961709Smlf if (flag & FEXCL) 11971709Smlf dkp->dk_open_exl |= partbit; 11981709Smlf 11991709Smlf mutex_exit(&dkp->dk_mutex); 12001709Smlf return (DDI_SUCCESS); 12011709Smlf 12021709Smlf excl_open_fail: 12031709Smlf mutex_exit(&dkp->dk_mutex); 12041709Smlf return (EBUSY); 12051709Smlf } 12061709Smlf 12071709Smlf /* 12081709Smlf * read routine 12091709Smlf */ 12101709Smlf /*ARGSUSED2*/ 12111709Smlf static int 12121709Smlf cmdkread(dev_t dev, struct uio *uio, cred_t *credp) 12131709Smlf { 12141709Smlf return (cmdkrw(dev, uio, B_READ)); 12151709Smlf } 12161709Smlf 12171709Smlf /* 12181709Smlf * async read routine 12191709Smlf */ 12201709Smlf /*ARGSUSED2*/ 12211709Smlf static int 12221709Smlf cmdkaread(dev_t dev, struct aio_req *aio, cred_t *credp) 12231709Smlf { 12241709Smlf return (cmdkarw(dev, aio, B_READ)); 12251709Smlf } 12261709Smlf 12271709Smlf /* 12281709Smlf * write routine 12291709Smlf */ 12301709Smlf /*ARGSUSED2*/ 12311709Smlf static int 12321709Smlf cmdkwrite(dev_t dev, struct uio *uio, cred_t *credp) 12331709Smlf { 12341709Smlf return (cmdkrw(dev, uio, B_WRITE)); 12351709Smlf } 12361709Smlf 12371709Smlf /* 12381709Smlf * async write routine 12391709Smlf */ 12401709Smlf /*ARGSUSED2*/ 12411709Smlf static int 12421709Smlf cmdkawrite(dev_t dev, struct aio_req *aio, cred_t *credp) 12431709Smlf { 12441709Smlf return (cmdkarw(dev, aio, B_WRITE)); 12451709Smlf } 12461709Smlf 12471709Smlf static void 12481709Smlf cmdkmin(struct buf *bp) 12491709Smlf { 12501709Smlf if (bp->b_bcount > DK_MAXRECSIZE) 12511709Smlf bp->b_bcount = DK_MAXRECSIZE; 12521709Smlf } 12531709Smlf 12541709Smlf static int 12551709Smlf cmdkrw(dev_t dev, struct uio *uio, int flag) 12561709Smlf { 12575295Srandyf int instance; 12585295Srandyf struct cmdk *dkp; 12595295Srandyf 12605295Srandyf instance = CMDKUNIT(dev); 12615295Srandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 12625295Srandyf return (ENXIO); 12635295Srandyf 12645295Srandyf mutex_enter(&dkp->dk_mutex); 12655295Srandyf while (dkp->dk_flag & CMDK_SUSPEND) { 12665295Srandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 12675295Srandyf } 12685295Srandyf mutex_exit(&dkp->dk_mutex); 12695295Srandyf 12701709Smlf return (physio(cmdkstrategy, (struct buf *)0, dev, flag, cmdkmin, uio)); 12711709Smlf } 12721709Smlf 12731709Smlf static int 12741709Smlf cmdkarw(dev_t dev, struct aio_req *aio, int flag) 12751709Smlf { 12765295Srandyf int instance; 12775295Srandyf struct cmdk *dkp; 12785295Srandyf 12795295Srandyf instance = CMDKUNIT(dev); 12805295Srandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 12815295Srandyf return (ENXIO); 12825295Srandyf 12835295Srandyf mutex_enter(&dkp->dk_mutex); 12845295Srandyf while (dkp->dk_flag & CMDK_SUSPEND) { 12855295Srandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 12865295Srandyf } 12875295Srandyf mutex_exit(&dkp->dk_mutex); 12885295Srandyf 12891709Smlf return (aphysio(cmdkstrategy, anocancel, dev, flag, cmdkmin, aio)); 12901709Smlf } 12911709Smlf 12921709Smlf /* 12931709Smlf * strategy routine 12941709Smlf */ 12951709Smlf static int 12961709Smlf cmdkstrategy(struct buf *bp) 12971709Smlf { 12981709Smlf int instance; 12991709Smlf struct cmdk *dkp; 13001709Smlf long d_cnt; 13011709Smlf diskaddr_t p_lblksrt; 13021709Smlf diskaddr_t p_lblkcnt; 13031709Smlf 13041709Smlf instance = CMDKUNIT(bp->b_edev); 13051709Smlf if (cmdk_indump || !(dkp = ddi_get_soft_state(cmdk_state, instance)) || 13061709Smlf (dkblock(bp) < 0)) { 13071709Smlf bp->b_resid = bp->b_bcount; 13081709Smlf SETBPERR(bp, ENXIO); 13091709Smlf biodone(bp); 13101709Smlf return (0); 13111709Smlf } 13121709Smlf 13135295Srandyf mutex_enter(&dkp->dk_mutex); 13146318Sedp ASSERT(cmdk_isopen(dkp, bp->b_edev)); 13155295Srandyf while (dkp->dk_flag & CMDK_SUSPEND) { 13165295Srandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 13175295Srandyf } 13185295Srandyf mutex_exit(&dkp->dk_mutex); 13195295Srandyf 13201709Smlf bp->b_flags &= ~(B_DONE|B_ERROR); 13211709Smlf bp->b_resid = 0; 13221709Smlf bp->av_back = NULL; 13231709Smlf 13241709Smlf /* 13251709Smlf * only re-read the vtoc if necessary (force == FALSE) 13261709Smlf */ 13273525Sshidokht if (cmlb_partinfo(dkp->dk_cmlbhandle, CMDKPART(bp->b_edev), 13283525Sshidokht &p_lblkcnt, &p_lblksrt, NULL, NULL, 0)) { 13291709Smlf SETBPERR(bp, ENXIO); 13301709Smlf } 13311709Smlf 13321709Smlf if ((bp->b_bcount & (NBPSCTR-1)) || (dkblock(bp) > p_lblkcnt)) 13331709Smlf SETBPERR(bp, ENXIO); 13341709Smlf 13351709Smlf if ((bp->b_flags & B_ERROR) || (dkblock(bp) == p_lblkcnt)) { 13361709Smlf bp->b_resid = bp->b_bcount; 13371709Smlf biodone(bp); 13381709Smlf return (0); 13391709Smlf } 13401709Smlf 13411709Smlf d_cnt = bp->b_bcount >> SCTRSHFT; 13421709Smlf if ((dkblock(bp) + d_cnt) > p_lblkcnt) { 13431709Smlf bp->b_resid = ((dkblock(bp) + d_cnt) - p_lblkcnt) << SCTRSHFT; 13441709Smlf bp->b_bcount -= bp->b_resid; 13451709Smlf } 13461709Smlf 13471709Smlf SET_BP_SEC(bp, ((ulong_t)(p_lblksrt + dkblock(bp)))); 13481709Smlf if (dadk_strategy(DKTP_DATA, bp) != DDI_SUCCESS) { 13491709Smlf bp->b_resid += bp->b_bcount; 13501709Smlf biodone(bp); 13511709Smlf } 13521709Smlf return (0); 13531709Smlf } 13541709Smlf 13551709Smlf static int 13561709Smlf cmdk_create_obj(dev_info_t *dip, struct cmdk *dkp) 13571709Smlf { 13581709Smlf struct scsi_device *devp; 13591709Smlf opaque_t queobjp = NULL; 13601709Smlf opaque_t flcobjp = NULL; 13611709Smlf char que_keyvalp[64]; 13621709Smlf int que_keylen; 13631709Smlf char flc_keyvalp[64]; 13641709Smlf int flc_keylen; 13651709Smlf 13661709Smlf ASSERT(mutex_owned(&dkp->dk_mutex)); 13671709Smlf 13681709Smlf /* Create linkage to queueing routines based on property */ 13691709Smlf que_keylen = sizeof (que_keyvalp); 13701709Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 13711709Smlf DDI_PROP_CANSLEEP, "queue", que_keyvalp, &que_keylen) != 13721709Smlf DDI_PROP_SUCCESS) { 13731709Smlf cmn_err(CE_WARN, "cmdk_create_obj: queue property undefined"); 13741709Smlf return (DDI_FAILURE); 13751709Smlf } 13761709Smlf que_keyvalp[que_keylen] = (char)0; 13771709Smlf 13781709Smlf if (strcmp(que_keyvalp, "qfifo") == 0) { 13791709Smlf queobjp = (opaque_t)qfifo_create(); 13801709Smlf } else if (strcmp(que_keyvalp, "qsort") == 0) { 13811709Smlf queobjp = (opaque_t)qsort_create(); 13821709Smlf } else { 13831709Smlf return (DDI_FAILURE); 13841709Smlf } 13851709Smlf 13861709Smlf /* Create linkage to dequeueing routines based on property */ 13871709Smlf flc_keylen = sizeof (flc_keyvalp); 13881709Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 13891709Smlf DDI_PROP_CANSLEEP, "flow_control", flc_keyvalp, &flc_keylen) != 13901709Smlf DDI_PROP_SUCCESS) { 13911709Smlf cmn_err(CE_WARN, 13921709Smlf "cmdk_create_obj: flow-control property undefined"); 13931709Smlf return (DDI_FAILURE); 13941709Smlf } 13951709Smlf 13961709Smlf flc_keyvalp[flc_keylen] = (char)0; 13971709Smlf 13981709Smlf if (strcmp(flc_keyvalp, "dsngl") == 0) { 13991709Smlf flcobjp = (opaque_t)dsngl_create(); 14001709Smlf } else if (strcmp(flc_keyvalp, "dmult") == 0) { 14011709Smlf flcobjp = (opaque_t)dmult_create(); 14021709Smlf } else { 14031709Smlf return (DDI_FAILURE); 14041709Smlf } 14051709Smlf 14061709Smlf /* populate bbh_obj object stored in dkp */ 14071709Smlf dkp->dk_bbh_obj.bbh_data = dkp; 14081709Smlf dkp->dk_bbh_obj.bbh_ops = &cmdk_bbh_ops; 14091709Smlf 14101709Smlf /* create linkage to dadk */ 14111709Smlf dkp->dk_tgobjp = (opaque_t)dadk_create(); 14121709Smlf 14131709Smlf devp = ddi_get_driver_private(dip); 14141709Smlf (void) dadk_init(DKTP_DATA, devp, flcobjp, queobjp, &dkp->dk_bbh_obj, 14151709Smlf NULL); 14161709Smlf 14171709Smlf return (DDI_SUCCESS); 14181709Smlf } 14191709Smlf 14201709Smlf static void 14211709Smlf cmdk_destroy_obj(dev_info_t *dip, struct cmdk *dkp) 14221709Smlf { 14231709Smlf char que_keyvalp[64]; 14241709Smlf int que_keylen; 14251709Smlf char flc_keyvalp[64]; 14261709Smlf int flc_keylen; 14271709Smlf 14281709Smlf ASSERT(mutex_owned(&dkp->dk_mutex)); 14291709Smlf 14301709Smlf (void) dadk_free((dkp->dk_tgobjp)); 14311709Smlf dkp->dk_tgobjp = NULL; 14321709Smlf 14331709Smlf que_keylen = sizeof (que_keyvalp); 14341709Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 14351709Smlf DDI_PROP_CANSLEEP, "queue", que_keyvalp, &que_keylen) != 14361709Smlf DDI_PROP_SUCCESS) { 14371709Smlf cmn_err(CE_WARN, "cmdk_destroy_obj: queue property undefined"); 14381709Smlf return; 14391709Smlf } 14401709Smlf que_keyvalp[que_keylen] = (char)0; 14411709Smlf 14421709Smlf flc_keylen = sizeof (flc_keyvalp); 14431709Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 14441709Smlf DDI_PROP_CANSLEEP, "flow_control", flc_keyvalp, &flc_keylen) != 14451709Smlf DDI_PROP_SUCCESS) { 14461709Smlf cmn_err(CE_WARN, 14471709Smlf "cmdk_destroy_obj: flow-control property undefined"); 14481709Smlf return; 14491709Smlf } 14501709Smlf flc_keyvalp[flc_keylen] = (char)0; 14511709Smlf } 14523525Sshidokht /*ARGSUSED5*/ 14531709Smlf static int 14543525Sshidokht cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr, 14553525Sshidokht diskaddr_t start, size_t count, void *tg_cookie) 14561709Smlf { 14571709Smlf struct cmdk *dkp; 14581709Smlf opaque_t handle; 14591709Smlf int rc = 0; 14601709Smlf char *bufa; 1461*11896SShidokht.Yadegari@Sun.COM size_t buflen; 14621709Smlf 14631709Smlf dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip)); 14641709Smlf if (dkp == NULL) 14651709Smlf return (ENXIO); 14661709Smlf 14671709Smlf if (cmd != TG_READ && cmd != TG_WRITE) 14681709Smlf return (EINVAL); 14691709Smlf 1470*11896SShidokht.Yadegari@Sun.COM /* buflen must be multiple of 512 */ 1471*11896SShidokht.Yadegari@Sun.COM buflen = (count + NBPSCTR - 1) & -NBPSCTR; 1472*11896SShidokht.Yadegari@Sun.COM handle = dadk_iob_alloc(DKTP_DATA, start, buflen, KM_SLEEP); 14731709Smlf if (!handle) 14741709Smlf return (ENOMEM); 14751709Smlf 14761709Smlf if (cmd == TG_READ) { 14771709Smlf bufa = dadk_iob_xfer(DKTP_DATA, handle, B_READ); 14781709Smlf if (!bufa) 14791709Smlf rc = EIO; 14801709Smlf else 14811709Smlf bcopy(bufa, bufaddr, count); 14821709Smlf } else { 14831709Smlf bufa = dadk_iob_htoc(DKTP_DATA, handle); 14841709Smlf bcopy(bufaddr, bufa, count); 14851709Smlf bufa = dadk_iob_xfer(DKTP_DATA, handle, B_WRITE); 14861709Smlf if (!bufa) 14871709Smlf rc = EIO; 14881709Smlf } 14891709Smlf (void) dadk_iob_free(DKTP_DATA, handle); 14901709Smlf 14911709Smlf return (rc); 14921709Smlf } 14931709Smlf 14943525Sshidokht /*ARGSUSED3*/ 14951709Smlf static int 14963525Sshidokht cmdk_lb_getinfo(dev_info_t *dip, int cmd, void *arg, void *tg_cookie) 14971709Smlf { 14983525Sshidokht 14991709Smlf struct cmdk *dkp; 15001709Smlf struct tgdk_geom phyg; 15011709Smlf 15021709Smlf 15031709Smlf dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip)); 15041709Smlf if (dkp == NULL) 15051709Smlf return (ENXIO); 15061709Smlf 15073525Sshidokht switch (cmd) { 15083525Sshidokht case TG_GETPHYGEOM: { 15093525Sshidokht cmlb_geom_t *phygeomp = (cmlb_geom_t *)arg; 15103525Sshidokht 15113525Sshidokht /* dadk_getphygeom always returns success */ 15123525Sshidokht (void) dadk_getphygeom(DKTP_DATA, &phyg); 15133525Sshidokht 15143525Sshidokht phygeomp->g_capacity = phyg.g_cap; 15153525Sshidokht phygeomp->g_nsect = phyg.g_sec; 15163525Sshidokht phygeomp->g_nhead = phyg.g_head; 15173525Sshidokht phygeomp->g_acyl = phyg.g_acyl; 15183525Sshidokht phygeomp->g_ncyl = phyg.g_cyl; 15193525Sshidokht phygeomp->g_secsize = phyg.g_secsiz; 15203525Sshidokht phygeomp->g_intrlv = 1; 15213525Sshidokht phygeomp->g_rpm = 3600; 15221709Smlf 15233525Sshidokht return (0); 15243525Sshidokht } 15253525Sshidokht 15263525Sshidokht case TG_GETVIRTGEOM: { 15273525Sshidokht cmlb_geom_t *virtgeomp = (cmlb_geom_t *)arg; 15283525Sshidokht diskaddr_t capacity; 15293525Sshidokht 15303525Sshidokht (void) dadk_getgeom(DKTP_DATA, &phyg); 15313525Sshidokht capacity = phyg.g_cap; 15323525Sshidokht 15333525Sshidokht /* 15343525Sshidokht * If the controller returned us something that doesn't 15353525Sshidokht * really fit into an Int 13/function 8 geometry 15363525Sshidokht * result, just fail the ioctl. See PSARC 1998/313. 15373525Sshidokht */ 15383525Sshidokht if (capacity < 0 || capacity >= 63 * 254 * 1024) 15393525Sshidokht return (EINVAL); 15401709Smlf 15413525Sshidokht virtgeomp->g_capacity = capacity; 15423525Sshidokht virtgeomp->g_nsect = 63; 15433525Sshidokht virtgeomp->g_nhead = 254; 15443525Sshidokht virtgeomp->g_ncyl = capacity / (63 * 254); 15453525Sshidokht virtgeomp->g_acyl = 0; 15463525Sshidokht virtgeomp->g_secsize = 512; 15473525Sshidokht virtgeomp->g_intrlv = 1; 15483525Sshidokht virtgeomp->g_rpm = 3600; 15493525Sshidokht 15503525Sshidokht return (0); 15513525Sshidokht } 15523525Sshidokht 15533525Sshidokht case TG_GETCAPACITY: 15543525Sshidokht case TG_GETBLOCKSIZE: 15553525Sshidokht { 15561709Smlf 15573525Sshidokht /* dadk_getphygeom always returns success */ 15583525Sshidokht (void) dadk_getphygeom(DKTP_DATA, &phyg); 15593525Sshidokht if (cmd == TG_GETCAPACITY) 15603525Sshidokht *(diskaddr_t *)arg = phyg.g_cap; 15613525Sshidokht else 15623525Sshidokht *(uint32_t *)arg = (uint32_t)phyg.g_secsiz; 15633525Sshidokht 15643525Sshidokht return (0); 15653525Sshidokht } 15663525Sshidokht 15673525Sshidokht case TG_GETATTR: { 15683525Sshidokht tg_attribute_t *tgattribute = (tg_attribute_t *)arg; 15693525Sshidokht if ((DKTP_EXT->tg_rdonly)) 15703525Sshidokht tgattribute->media_is_writable = FALSE; 15713525Sshidokht else 15723525Sshidokht tgattribute->media_is_writable = TRUE; 15733525Sshidokht 15743525Sshidokht return (0); 15753525Sshidokht } 15763525Sshidokht 15773525Sshidokht default: 15783525Sshidokht return (ENOTTY); 15793525Sshidokht } 15801709Smlf } 15811709Smlf 15821709Smlf 15831709Smlf 15841709Smlf 15851709Smlf 15861709Smlf /* 15871709Smlf * Create and register the devid. 15881709Smlf * There are 4 different ways we can get a device id: 15891709Smlf * 1. Already have one - nothing to do 15901709Smlf * 2. Build one from the drive's model and serial numbers 15911709Smlf * 3. Read one from the disk (first sector of last track) 15921709Smlf * 4. Fabricate one and write it on the disk. 15931709Smlf * If any of these succeeds, register the deviceid 15941709Smlf */ 15951709Smlf static void 15961709Smlf cmdk_devid_setup(struct cmdk *dkp) 15971709Smlf { 15981709Smlf int rc; 15991709Smlf 16001709Smlf /* Try options until one succeeds, or all have failed */ 16011709Smlf 16021709Smlf /* 1. All done if already registered */ 16031709Smlf if (dkp->dk_devid != NULL) 16041709Smlf return; 16051709Smlf 16061709Smlf /* 2. Build a devid from the model and serial number */ 16071709Smlf rc = cmdk_devid_modser(dkp); 16081709Smlf if (rc != DDI_SUCCESS) { 16091709Smlf /* 3. Read devid from the disk, if present */ 16101709Smlf rc = cmdk_devid_read(dkp); 16111709Smlf 16121709Smlf /* 4. otherwise make one up and write it on the disk */ 16131709Smlf if (rc != DDI_SUCCESS) 16141709Smlf rc = cmdk_devid_fabricate(dkp); 16151709Smlf } 16161709Smlf 16171709Smlf /* If we managed to get a devid any of the above ways, register it */ 16181709Smlf if (rc == DDI_SUCCESS) 16191709Smlf (void) ddi_devid_register(dkp->dk_dip, dkp->dk_devid); 16201709Smlf 16211709Smlf } 16221709Smlf 16231709Smlf /* 16241709Smlf * Build a devid from the model and serial number 16251709Smlf * Return DDI_SUCCESS or DDI_FAILURE. 16261709Smlf */ 16271709Smlf static int 16281709Smlf cmdk_devid_modser(struct cmdk *dkp) 16291709Smlf { 16301709Smlf int rc = DDI_FAILURE; 16311709Smlf char *hwid; 16321709Smlf int modlen; 16331709Smlf int serlen; 16341709Smlf 16351709Smlf /* 16361709Smlf * device ID is a concatenation of model number, '=', serial number. 16371709Smlf */ 16381709Smlf hwid = kmem_alloc(CMDK_HWIDLEN, KM_SLEEP); 16391709Smlf modlen = cmdk_get_modser(dkp, DIOCTL_GETMODEL, hwid, CMDK_HWIDLEN); 16401709Smlf if (modlen == 0) { 16411709Smlf rc = DDI_FAILURE; 16421709Smlf goto err; 16431709Smlf } 16441709Smlf hwid[modlen++] = '='; 16451709Smlf serlen = cmdk_get_modser(dkp, DIOCTL_GETSERIAL, 16461709Smlf hwid + modlen, CMDK_HWIDLEN - modlen); 16471709Smlf if (serlen == 0) { 16481709Smlf rc = DDI_FAILURE; 16491709Smlf goto err; 16501709Smlf } 16511709Smlf hwid[modlen + serlen] = 0; 16521709Smlf 16531709Smlf /* Initialize the device ID, trailing NULL not included */ 16541709Smlf rc = ddi_devid_init(dkp->dk_dip, DEVID_ATA_SERIAL, modlen + serlen, 16557666SMark.Logan@Sun.COM hwid, &dkp->dk_devid); 16561709Smlf if (rc != DDI_SUCCESS) { 16571709Smlf rc = DDI_FAILURE; 16581709Smlf goto err; 16591709Smlf } 16601709Smlf 16611709Smlf rc = DDI_SUCCESS; 16621709Smlf 16631709Smlf err: 16641709Smlf kmem_free(hwid, CMDK_HWIDLEN); 16651709Smlf return (rc); 16661709Smlf } 16671709Smlf 16681709Smlf static int 16691709Smlf cmdk_get_modser(struct cmdk *dkp, int ioccmd, char *buf, int len) 16701709Smlf { 16711709Smlf dadk_ioc_string_t strarg; 16721709Smlf int rval; 16731709Smlf char *s; 16741709Smlf char ch; 16751709Smlf boolean_t ret; 16761709Smlf int i; 16771709Smlf int tb; 16781709Smlf 16791709Smlf strarg.is_buf = buf; 16801709Smlf strarg.is_size = len; 16811709Smlf if (dadk_ioctl(DKTP_DATA, 16821709Smlf dkp->dk_dev, 16831709Smlf ioccmd, 16841709Smlf (uintptr_t)&strarg, 16851709Smlf FNATIVE | FKIOCTL, 16861709Smlf NULL, 16871709Smlf &rval) != 0) 16881709Smlf return (0); 16891709Smlf 16901709Smlf /* 16911709Smlf * valid model/serial string must contain a non-zero non-space 16921709Smlf * trim trailing spaces/NULL 16931709Smlf */ 16941709Smlf ret = B_FALSE; 16951709Smlf s = buf; 16961709Smlf for (i = 0; i < strarg.is_size; i++) { 16971709Smlf ch = *s++; 16981709Smlf if (ch != ' ' && ch != '\0') 16991709Smlf tb = i + 1; 17001709Smlf if (ch != ' ' && ch != '\0' && ch != '0') 17011709Smlf ret = B_TRUE; 17021709Smlf } 17031709Smlf 17041709Smlf if (ret == B_FALSE) 17051709Smlf return (0); 17061709Smlf 17071709Smlf return (tb); 17081709Smlf } 17091709Smlf 17101709Smlf /* 17111709Smlf * Read a devid from on the first block of the last track of 17121709Smlf * the last cylinder. Make sure what we read is a valid devid. 17131709Smlf * Return DDI_SUCCESS or DDI_FAILURE. 17141709Smlf */ 17151709Smlf static int 17161709Smlf cmdk_devid_read(struct cmdk *dkp) 17171709Smlf { 17181709Smlf diskaddr_t blk; 17191709Smlf struct dk_devid *dkdevidp; 17201709Smlf uint_t *ip; 17211709Smlf int chksum; 17221709Smlf int i, sz; 17237573SMark.Logan@Sun.COM tgdk_iob_handle handle = NULL; 17241709Smlf int rc = DDI_FAILURE; 17251709Smlf 17263525Sshidokht if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0)) 17271709Smlf goto err; 17281709Smlf 17291709Smlf /* read the devid */ 17301709Smlf handle = dadk_iob_alloc(DKTP_DATA, blk, NBPSCTR, KM_SLEEP); 17311709Smlf if (handle == NULL) 17321709Smlf goto err; 17331709Smlf 17341709Smlf dkdevidp = (struct dk_devid *)dadk_iob_xfer(DKTP_DATA, handle, B_READ); 17351709Smlf if (dkdevidp == NULL) 17361709Smlf goto err; 17371709Smlf 17381709Smlf /* Validate the revision */ 17391709Smlf if ((dkdevidp->dkd_rev_hi != DK_DEVID_REV_MSB) || 17401709Smlf (dkdevidp->dkd_rev_lo != DK_DEVID_REV_LSB)) 17411709Smlf goto err; 17421709Smlf 17431709Smlf /* Calculate the checksum */ 17441709Smlf chksum = 0; 17451709Smlf ip = (uint_t *)dkdevidp; 17461709Smlf for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++) 17471709Smlf chksum ^= ip[i]; 17481709Smlf if (DKD_GETCHKSUM(dkdevidp) != chksum) 17491709Smlf goto err; 17501709Smlf 17511709Smlf /* Validate the device id */ 17521709Smlf if (ddi_devid_valid((ddi_devid_t)dkdevidp->dkd_devid) != DDI_SUCCESS) 17531709Smlf goto err; 17541709Smlf 17551709Smlf /* keep a copy of the device id */ 17561709Smlf sz = ddi_devid_sizeof((ddi_devid_t)dkdevidp->dkd_devid); 17571709Smlf dkp->dk_devid = kmem_alloc(sz, KM_SLEEP); 17581709Smlf bcopy(dkdevidp->dkd_devid, dkp->dk_devid, sz); 17591709Smlf 17601709Smlf rc = DDI_SUCCESS; 17611709Smlf 17621709Smlf err: 17631709Smlf if (handle != NULL) 17641709Smlf (void) dadk_iob_free(DKTP_DATA, handle); 17651709Smlf return (rc); 17661709Smlf } 17671709Smlf 17681709Smlf /* 17691709Smlf * Create a devid and write it on the first block of the last track of 17701709Smlf * the last cylinder. 17711709Smlf * Return DDI_SUCCESS or DDI_FAILURE. 17721709Smlf */ 17731709Smlf static int 17741709Smlf cmdk_devid_fabricate(struct cmdk *dkp) 17751709Smlf { 17761709Smlf ddi_devid_t devid = NULL; /* devid made by ddi_devid_init */ 17771709Smlf struct dk_devid *dkdevidp; /* devid struct stored on disk */ 17781709Smlf diskaddr_t blk; 17791709Smlf tgdk_iob_handle handle = NULL; 17801709Smlf uint_t *ip, chksum; 17811709Smlf int i; 17827666SMark.Logan@Sun.COM int rc = DDI_FAILURE; 17831709Smlf 17847666SMark.Logan@Sun.COM if (ddi_devid_init(dkp->dk_dip, DEVID_FAB, 0, NULL, &devid) != 17857666SMark.Logan@Sun.COM DDI_SUCCESS) 17861709Smlf goto err; 17871709Smlf 17883525Sshidokht if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0)) { 17891709Smlf /* no device id block address */ 17907666SMark.Logan@Sun.COM goto err; 17911709Smlf } 17921709Smlf 17931709Smlf handle = dadk_iob_alloc(DKTP_DATA, blk, NBPSCTR, KM_SLEEP); 17941709Smlf if (!handle) 17951709Smlf goto err; 17961709Smlf 17971709Smlf /* Locate the buffer */ 17981709Smlf dkdevidp = (struct dk_devid *)dadk_iob_htoc(DKTP_DATA, handle); 17991709Smlf 18001709Smlf /* Fill in the revision */ 18011709Smlf bzero(dkdevidp, NBPSCTR); 18021709Smlf dkdevidp->dkd_rev_hi = DK_DEVID_REV_MSB; 18031709Smlf dkdevidp->dkd_rev_lo = DK_DEVID_REV_LSB; 18041709Smlf 18051709Smlf /* Copy in the device id */ 18061709Smlf i = ddi_devid_sizeof(devid); 18071709Smlf if (i > DK_DEVID_SIZE) 18081709Smlf goto err; 18091709Smlf bcopy(devid, dkdevidp->dkd_devid, i); 18101709Smlf 18111709Smlf /* Calculate the chksum */ 18121709Smlf chksum = 0; 18131709Smlf ip = (uint_t *)dkdevidp; 18141709Smlf for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++) 18151709Smlf chksum ^= ip[i]; 18161709Smlf 18171709Smlf /* Fill in the checksum */ 18181709Smlf DKD_FORMCHKSUM(chksum, dkdevidp); 18191709Smlf 18201709Smlf /* write the devid */ 18211709Smlf (void) dadk_iob_xfer(DKTP_DATA, handle, B_WRITE); 18221709Smlf 18231709Smlf dkp->dk_devid = devid; 18241709Smlf 18251709Smlf rc = DDI_SUCCESS; 18261709Smlf 18271709Smlf err: 18281709Smlf if (handle != NULL) 18291709Smlf (void) dadk_iob_free(DKTP_DATA, handle); 18301709Smlf 18311709Smlf if (rc != DDI_SUCCESS && devid != NULL) 18321709Smlf ddi_devid_free(devid); 18331709Smlf 18341709Smlf return (rc); 18351709Smlf } 18361709Smlf 18371709Smlf static void 18381709Smlf cmdk_bbh_free_alts(struct cmdk *dkp) 18391709Smlf { 18401709Smlf if (dkp->dk_alts_hdl) { 18411709Smlf (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl); 18421709Smlf kmem_free(dkp->dk_slc_cnt, 18431709Smlf NDKMAP * (sizeof (uint32_t) + sizeof (struct alts_ent *))); 18441709Smlf dkp->dk_alts_hdl = NULL; 18451709Smlf } 18461709Smlf } 18471709Smlf 18481709Smlf static void 18491709Smlf cmdk_bbh_reopen(struct cmdk *dkp) 18501709Smlf { 18511709Smlf tgdk_iob_handle handle = NULL; 18521709Smlf diskaddr_t slcb, slcn, slce; 18531709Smlf struct alts_parttbl *ap; 18541709Smlf struct alts_ent *enttblp; 18551709Smlf uint32_t altused; 18561709Smlf uint32_t altbase; 18571709Smlf uint32_t altlast; 18581709Smlf int alts; 18591709Smlf uint16_t vtoctag; 18601709Smlf int i, j; 18611709Smlf 18621709Smlf /* find slice with V_ALTSCTR tag */ 18631709Smlf for (alts = 0; alts < NDKMAP; alts++) { 18641709Smlf if (cmlb_partinfo( 18651709Smlf dkp->dk_cmlbhandle, 18661709Smlf alts, 18671709Smlf &slcn, 18681709Smlf &slcb, 18691709Smlf NULL, 18703525Sshidokht &vtoctag, 18713525Sshidokht 0)) { 18721709Smlf goto empty; /* no partition table exists */ 18731709Smlf } 18741709Smlf 18751709Smlf if (vtoctag == V_ALTSCTR && slcn > 1) 18761709Smlf break; 18771709Smlf } 18781709Smlf if (alts >= NDKMAP) { 18791709Smlf goto empty; /* no V_ALTSCTR slice defined */ 18801709Smlf } 18811709Smlf 18821709Smlf /* read in ALTS label block */ 18831709Smlf handle = dadk_iob_alloc(DKTP_DATA, slcb, NBPSCTR, KM_SLEEP); 18841709Smlf if (!handle) { 18851709Smlf goto empty; 18861709Smlf } 18871709Smlf 18881709Smlf ap = (struct alts_parttbl *)dadk_iob_xfer(DKTP_DATA, handle, B_READ); 18891709Smlf if (!ap || (ap->alts_sanity != ALTS_SANITY)) { 18901709Smlf goto empty; 18911709Smlf } 18921709Smlf 18931709Smlf altused = ap->alts_ent_used; /* number of BB entries */ 18941709Smlf altbase = ap->alts_ent_base; /* blk offset from begin slice */ 18951709Smlf altlast = ap->alts_ent_end; /* blk offset to last block */ 18961709Smlf /* ((altused * sizeof (struct alts_ent) + NBPSCTR - 1) & ~NBPSCTR) */ 18971709Smlf 18981709Smlf if (altused == 0 || 18991709Smlf altbase < 1 || 19001709Smlf altbase > altlast || 19011709Smlf altlast >= slcn) { 19021709Smlf goto empty; 19031709Smlf } 19041709Smlf (void) dadk_iob_free(DKTP_DATA, handle); 19051709Smlf 19061709Smlf /* read in ALTS remapping table */ 19071709Smlf handle = dadk_iob_alloc(DKTP_DATA, 19081709Smlf slcb + altbase, 19091709Smlf (altlast - altbase + 1) << SCTRSHFT, KM_SLEEP); 19101709Smlf if (!handle) { 19111709Smlf goto empty; 19121709Smlf } 19131709Smlf 19141709Smlf enttblp = (struct alts_ent *)dadk_iob_xfer(DKTP_DATA, handle, B_READ); 19151709Smlf if (!enttblp) { 19161709Smlf goto empty; 19171709Smlf } 19181709Smlf 19191709Smlf rw_enter(&dkp->dk_bbh_mutex, RW_WRITER); 19201709Smlf 19211709Smlf /* allocate space for dk_slc_cnt and dk_slc_ent tables */ 19221709Smlf if (dkp->dk_slc_cnt == NULL) { 19231709Smlf dkp->dk_slc_cnt = kmem_alloc(NDKMAP * 19241709Smlf (sizeof (long) + sizeof (struct alts_ent *)), KM_SLEEP); 19251709Smlf } 19261709Smlf dkp->dk_slc_ent = (struct alts_ent **)(dkp->dk_slc_cnt + NDKMAP); 19271709Smlf 19281709Smlf /* free previous BB table (if any) */ 19291709Smlf if (dkp->dk_alts_hdl) { 19301709Smlf (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl); 19311709Smlf dkp->dk_alts_hdl = NULL; 19321709Smlf dkp->dk_altused = 0; 19331709Smlf } 19341709Smlf 19351709Smlf /* save linkage to new BB table */ 19361709Smlf dkp->dk_alts_hdl = handle; 19371709Smlf dkp->dk_altused = altused; 19381709Smlf 19391709Smlf /* 19401709Smlf * build indexes to BB table by slice 19411709Smlf * effectively we have 19421709Smlf * struct alts_ent *enttblp[altused]; 19431709Smlf * 19441709Smlf * uint32_t dk_slc_cnt[NDKMAP]; 19451709Smlf * struct alts_ent *dk_slc_ent[NDKMAP]; 19461709Smlf */ 19471709Smlf for (i = 0; i < NDKMAP; i++) { 19481709Smlf if (cmlb_partinfo( 19491709Smlf dkp->dk_cmlbhandle, 19501709Smlf i, 19511709Smlf &slcn, 19521709Smlf &slcb, 19531709Smlf NULL, 19543525Sshidokht NULL, 19553525Sshidokht 0)) { 19561709Smlf goto empty1; 19571709Smlf } 19581709Smlf 19591709Smlf dkp->dk_slc_cnt[i] = 0; 19601709Smlf if (slcn == 0) 19611709Smlf continue; /* slice is not allocated */ 19621709Smlf 19631709Smlf /* last block in slice */ 19641709Smlf slce = slcb + slcn - 1; 19651709Smlf 19661709Smlf /* find first remap entry in after beginnning of slice */ 19671709Smlf for (j = 0; j < altused; j++) { 19681709Smlf if (enttblp[j].bad_start + enttblp[j].bad_end >= slcb) 19691709Smlf break; 19701709Smlf } 19711709Smlf dkp->dk_slc_ent[i] = enttblp + j; 19721709Smlf 19731709Smlf /* count remap entrys until end of slice */ 19741709Smlf for (; j < altused && enttblp[j].bad_start <= slce; j++) { 19751709Smlf dkp->dk_slc_cnt[i] += 1; 19761709Smlf } 19771709Smlf } 19781709Smlf 19791709Smlf rw_exit(&dkp->dk_bbh_mutex); 19801709Smlf return; 19811709Smlf 19821709Smlf empty: 19831709Smlf rw_enter(&dkp->dk_bbh_mutex, RW_WRITER); 19841709Smlf empty1: 19851709Smlf if (handle && handle != dkp->dk_alts_hdl) 19861709Smlf (void) dadk_iob_free(DKTP_DATA, handle); 19871709Smlf 19881709Smlf if (dkp->dk_alts_hdl) { 19891709Smlf (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl); 19901709Smlf dkp->dk_alts_hdl = NULL; 19911709Smlf } 19921709Smlf 19931709Smlf rw_exit(&dkp->dk_bbh_mutex); 19941709Smlf } 19951709Smlf 19961709Smlf /*ARGSUSED*/ 19971709Smlf static bbh_cookie_t 19981709Smlf cmdk_bbh_htoc(opaque_t bbh_data, opaque_t handle) 19991709Smlf { 20001709Smlf struct bbh_handle *hp; 20011709Smlf bbh_cookie_t ckp; 20021709Smlf 20031709Smlf hp = (struct bbh_handle *)handle; 20041709Smlf ckp = hp->h_cktab + hp->h_idx; 20051709Smlf hp->h_idx++; 20061709Smlf return (ckp); 20071709Smlf } 20081709Smlf 20091709Smlf /*ARGSUSED*/ 20101709Smlf static void 20111709Smlf cmdk_bbh_freehandle(opaque_t bbh_data, opaque_t handle) 20121709Smlf { 20131709Smlf struct bbh_handle *hp; 20141709Smlf 20151709Smlf hp = (struct bbh_handle *)handle; 20161709Smlf kmem_free(handle, (sizeof (struct bbh_handle) + 20171709Smlf (hp->h_totck * (sizeof (struct bbh_cookie))))); 20181709Smlf } 20191709Smlf 20201709Smlf 20211709Smlf /* 20221709Smlf * cmdk_bbh_gethandle remaps the bad sectors to alternates. 20231709Smlf * There are 7 different cases when the comparison is made 20241709Smlf * between the bad sector cluster and the disk section. 20251709Smlf * 20261709Smlf * bad sector cluster gggggggggggbbbbbbbggggggggggg 20271709Smlf * case 1: ddddd 20281709Smlf * case 2: -d----- 20291709Smlf * case 3: ddddd 20301709Smlf * case 4: dddddddddddd 20311709Smlf * case 5: ddddddd----- 20321709Smlf * case 6: ---ddddddd 20331709Smlf * case 7: ddddddd 20341709Smlf * 20351709Smlf * where: g = good sector, b = bad sector 20361709Smlf * d = sector in disk section 20371709Smlf * - = disk section may be extended to cover those disk area 20381709Smlf */ 20391709Smlf 20401709Smlf static opaque_t 20411709Smlf cmdk_bbh_gethandle(opaque_t bbh_data, struct buf *bp) 20421709Smlf { 20431709Smlf struct cmdk *dkp = (struct cmdk *)bbh_data; 20441709Smlf struct bbh_handle *hp; 20451709Smlf struct bbh_cookie *ckp; 20461709Smlf struct alts_ent *altp; 20471709Smlf uint32_t alts_used; 20481709Smlf uint32_t part = CMDKPART(bp->b_edev); 20491709Smlf daddr32_t lastsec; 20501709Smlf long d_count; 20511709Smlf int i; 20521709Smlf int idx; 20531709Smlf int cnt; 20541709Smlf 20551709Smlf if (part >= V_NUMPAR) 20561709Smlf return (NULL); 20571709Smlf 20581709Smlf /* 20591709Smlf * This if statement is atomic and it will succeed 20601709Smlf * if there are no bad blocks (almost always) 20611709Smlf * 20621709Smlf * so this if is performed outside of the rw_enter for speed 20631709Smlf * and then repeated inside the rw_enter for safety 20641709Smlf */ 20651709Smlf if (!dkp->dk_alts_hdl) { 20661709Smlf return (NULL); 20671709Smlf } 20681709Smlf 20691709Smlf rw_enter(&dkp->dk_bbh_mutex, RW_READER); 20701709Smlf 20711709Smlf if (dkp->dk_alts_hdl == NULL) { 20721709Smlf rw_exit(&dkp->dk_bbh_mutex); 20731709Smlf return (NULL); 20741709Smlf } 20751709Smlf 20761709Smlf alts_used = dkp->dk_slc_cnt[part]; 20771709Smlf if (alts_used == 0) { 20781709Smlf rw_exit(&dkp->dk_bbh_mutex); 20791709Smlf return (NULL); 20801709Smlf } 20811709Smlf altp = dkp->dk_slc_ent[part]; 20821709Smlf 20831709Smlf /* 20841709Smlf * binary search for the largest bad sector index in the alternate 20851709Smlf * entry table which overlaps or larger than the starting d_sec 20861709Smlf */ 20871709Smlf i = cmdk_bbh_bsearch(altp, alts_used, GET_BP_SEC(bp)); 20881709Smlf /* if starting sector is > the largest bad sector, return */ 20891709Smlf if (i == -1) { 20901709Smlf rw_exit(&dkp->dk_bbh_mutex); 20911709Smlf return (NULL); 20921709Smlf } 20931709Smlf /* i is the starting index. Set altp to the starting entry addr */ 20941709Smlf altp += i; 20951709Smlf 20961709Smlf d_count = bp->b_bcount >> SCTRSHFT; 20971709Smlf lastsec = GET_BP_SEC(bp) + d_count - 1; 20981709Smlf 20991709Smlf /* calculate the number of bad sectors */ 21001709Smlf for (idx = i, cnt = 0; idx < alts_used; idx++, altp++, cnt++) { 21011709Smlf if (lastsec < altp->bad_start) 21021709Smlf break; 21031709Smlf } 21041709Smlf 21051709Smlf if (!cnt) { 21061709Smlf rw_exit(&dkp->dk_bbh_mutex); 21071709Smlf return (NULL); 21081709Smlf } 21091709Smlf 21101709Smlf /* calculate the maximum number of reserved cookies */ 21111709Smlf cnt <<= 1; 21121709Smlf cnt++; 21131709Smlf 21141709Smlf /* allocate the handle */ 21151709Smlf hp = (struct bbh_handle *)kmem_zalloc((sizeof (*hp) + 21161709Smlf (cnt * sizeof (*ckp))), KM_SLEEP); 21171709Smlf 21181709Smlf hp->h_idx = 0; 21191709Smlf hp->h_totck = cnt; 21201709Smlf ckp = hp->h_cktab = (struct bbh_cookie *)(hp + 1); 21211709Smlf ckp[0].ck_sector = GET_BP_SEC(bp); 21221709Smlf ckp[0].ck_seclen = d_count; 21231709Smlf 21241709Smlf altp = dkp->dk_slc_ent[part]; 21251709Smlf altp += i; 21261709Smlf for (idx = 0; i < alts_used; i++, altp++) { 21271709Smlf /* CASE 1: */ 21281709Smlf if (lastsec < altp->bad_start) 21291709Smlf break; 21301709Smlf 21311709Smlf /* CASE 3: */ 21321709Smlf if (ckp[idx].ck_sector > altp->bad_end) 21331709Smlf continue; 21341709Smlf 21351709Smlf /* CASE 2 and 7: */ 21361709Smlf if ((ckp[idx].ck_sector >= altp->bad_start) && 21371709Smlf (lastsec <= altp->bad_end)) { 21381709Smlf ckp[idx].ck_sector = altp->good_start + 21391709Smlf ckp[idx].ck_sector - altp->bad_start; 21401709Smlf break; 21411709Smlf } 21421709Smlf 21431709Smlf /* at least one bad sector in our section. break it. */ 21441709Smlf /* CASE 5: */ 21451709Smlf if ((lastsec >= altp->bad_start) && 21465295Srandyf (lastsec <= altp->bad_end)) { 21471709Smlf ckp[idx+1].ck_seclen = lastsec - altp->bad_start + 1; 21481709Smlf ckp[idx].ck_seclen -= ckp[idx+1].ck_seclen; 21491709Smlf ckp[idx+1].ck_sector = altp->good_start; 21501709Smlf break; 21511709Smlf } 21521709Smlf /* CASE 6: */ 21531709Smlf if ((ckp[idx].ck_sector <= altp->bad_end) && 21541709Smlf (ckp[idx].ck_sector >= altp->bad_start)) { 21551709Smlf ckp[idx+1].ck_seclen = ckp[idx].ck_seclen; 21561709Smlf ckp[idx].ck_seclen = altp->bad_end - 21571709Smlf ckp[idx].ck_sector + 1; 21581709Smlf ckp[idx+1].ck_seclen -= ckp[idx].ck_seclen; 21591709Smlf ckp[idx].ck_sector = altp->good_start + 21601709Smlf ckp[idx].ck_sector - altp->bad_start; 21611709Smlf idx++; 21621709Smlf ckp[idx].ck_sector = altp->bad_end + 1; 21631709Smlf continue; /* check rest of section */ 21641709Smlf } 21651709Smlf 21661709Smlf /* CASE 4: */ 21671709Smlf ckp[idx].ck_seclen = altp->bad_start - ckp[idx].ck_sector; 21681709Smlf ckp[idx+1].ck_sector = altp->good_start; 21691709Smlf ckp[idx+1].ck_seclen = altp->bad_end - altp->bad_start + 1; 21701709Smlf idx += 2; 21711709Smlf ckp[idx].ck_sector = altp->bad_end + 1; 21721709Smlf ckp[idx].ck_seclen = lastsec - altp->bad_end; 21731709Smlf } 21741709Smlf 21751709Smlf rw_exit(&dkp->dk_bbh_mutex); 21761709Smlf return ((opaque_t)hp); 21771709Smlf } 21781709Smlf 21791709Smlf static int 21801709Smlf cmdk_bbh_bsearch(struct alts_ent *buf, int cnt, daddr32_t key) 21811709Smlf { 21821709Smlf int i; 21831709Smlf int ind; 21841709Smlf int interval; 21851709Smlf int mystatus = -1; 21861709Smlf 21871709Smlf if (!cnt) 21881709Smlf return (mystatus); 21891709Smlf 21901709Smlf ind = 1; /* compiler complains about possible uninitialized var */ 21911709Smlf for (i = 1; i <= cnt; i <<= 1) 21921709Smlf ind = i; 21931709Smlf 21941709Smlf for (interval = ind; interval; ) { 21951709Smlf if ((key >= buf[ind-1].bad_start) && 21961709Smlf (key <= buf[ind-1].bad_end)) { 21971709Smlf return (ind-1); 21981709Smlf } else { 21991709Smlf interval >>= 1; 22001709Smlf if (key < buf[ind-1].bad_start) { 22011709Smlf /* record the largest bad sector index */ 22021709Smlf mystatus = ind-1; 22031709Smlf if (!interval) 22041709Smlf break; 22051709Smlf ind = ind - interval; 22061709Smlf } else { 22071709Smlf /* 22081709Smlf * if key is larger than the last element 22091709Smlf * then break 22101709Smlf */ 22111709Smlf if ((ind == cnt) || !interval) 22121709Smlf break; 22131709Smlf if ((ind+interval) <= cnt) 22141709Smlf ind += interval; 22151709Smlf } 22161709Smlf } 22171709Smlf } 22181709Smlf return (mystatus); 22191709Smlf } 2220