xref: /onnv-gate/usr/src/uts/intel/io/dktp/disk/cmdk.c (revision 13067:9c11d9f612c8)
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