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