xref: /titanic_52/usr/src/uts/intel/io/dktp/disk/cmdk.c (revision b2b61b8f39b7aee60b768425b878e162628e8cf3)
1507c3241Smlf /*
2507c3241Smlf  * CDDL HEADER START
3507c3241Smlf  *
4507c3241Smlf  * The contents of this file are subject to the terms of the
5e8fb11a1Sshidokht  * Common Development and Distribution License (the "License").
6e8fb11a1Sshidokht  * You may not use this file except in compliance with the License.
7507c3241Smlf  *
8507c3241Smlf  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9507c3241Smlf  * or http://www.opensolaris.org/os/licensing.
10507c3241Smlf  * See the License for the specific language governing permissions
11507c3241Smlf  * and limitations under the License.
12507c3241Smlf  *
13507c3241Smlf  * When distributing Covered Code, include this CDDL HEADER in each
14507c3241Smlf  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15507c3241Smlf  * If applicable, add the following below this CDDL HEADER, with the
16507c3241Smlf  * fields enclosed by brackets "[]" replaced with your own identifying
17507c3241Smlf  * information: Portions Copyright [yyyy] [name of copyright owner]
18507c3241Smlf  *
19507c3241Smlf  * CDDL HEADER END
20507c3241Smlf  */
21342440ecSPrasad Singamsetty 
22507c3241Smlf /*
238b6b46faSzhongyan gu - Sun Microsystems - Beijing China  * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
24507c3241Smlf  */
25507c3241Smlf 
26507c3241Smlf #include <sys/scsi/scsi.h>
27507c3241Smlf #include <sys/dktp/cm.h>
28507c3241Smlf #include <sys/dktp/quetypes.h>
29507c3241Smlf #include <sys/dktp/queue.h>
30507c3241Smlf #include <sys/dktp/fctypes.h>
31507c3241Smlf #include <sys/dktp/flowctrl.h>
32507c3241Smlf #include <sys/dktp/cmdev.h>
33507c3241Smlf #include <sys/dkio.h>
34507c3241Smlf #include <sys/dktp/tgdk.h>
35507c3241Smlf #include <sys/dktp/dadk.h>
36507c3241Smlf #include <sys/dktp/bbh.h>
37507c3241Smlf #include <sys/dktp/altsctr.h>
38507c3241Smlf #include <sys/dktp/cmdk.h>
39507c3241Smlf 
40507c3241Smlf #include <sys/stat.h>
41507c3241Smlf #include <sys/vtoc.h>
42507c3241Smlf #include <sys/file.h>
43507c3241Smlf #include <sys/dktp/dadkio.h>
44507c3241Smlf #include <sys/aio_req.h>
45507c3241Smlf 
46507c3241Smlf #include <sys/cmlb.h>
47507c3241Smlf 
48507c3241Smlf /*
49507c3241Smlf  * Local Static Data
50507c3241Smlf  */
51507c3241Smlf #ifdef CMDK_DEBUG
52507c3241Smlf #define	DENT	0x0001
53507c3241Smlf #define	DIO	0x0002
54507c3241Smlf 
55507c3241Smlf static	int	cmdk_debug = DIO;
56507c3241Smlf #endif
57507c3241Smlf 
58507c3241Smlf #ifndef	TRUE
59507c3241Smlf #define	TRUE	1
60507c3241Smlf #endif
61507c3241Smlf 
62507c3241Smlf #ifndef	FALSE
63507c3241Smlf #define	FALSE	0
64507c3241Smlf #endif
65507c3241Smlf 
66507c3241Smlf /*
67507c3241Smlf  * NDKMAP is the base number for accessing the fdisk partitions.
68507c3241Smlf  * c?d?p0 --> cmdk@?,?:q
69507c3241Smlf  */
70507c3241Smlf #define	PARTITION0_INDEX	(NDKMAP + 0)
71507c3241Smlf 
72507c3241Smlf #define	DKTP_DATA		(dkp->dk_tgobjp)->tg_data
73507c3241Smlf #define	DKTP_EXT		(dkp->dk_tgobjp)->tg_ext
74507c3241Smlf 
757f0b8309SEdward Pilatowicz void *cmdk_state;
76507c3241Smlf 
77507c3241Smlf /*
78507c3241Smlf  * the cmdk_attach_mutex protects cmdk_max_instance in multi-threaded
79507c3241Smlf  * attach situations
80507c3241Smlf  */
81507c3241Smlf static kmutex_t cmdk_attach_mutex;
82507c3241Smlf static int cmdk_max_instance = 0;
83507c3241Smlf 
84507c3241Smlf /*
85507c3241Smlf  * Panic dumpsys state
86507c3241Smlf  * There is only a single flag that is not mutex locked since
87507c3241Smlf  * the system is prevented from thread switching and cmdk_dump
88507c3241Smlf  * will only be called in a single threaded operation.
89507c3241Smlf  */
90507c3241Smlf static int	cmdk_indump;
91507c3241Smlf 
92507c3241Smlf /*
93507c3241Smlf  * Local Function Prototypes
94507c3241Smlf  */
95507c3241Smlf static int cmdk_create_obj(dev_info_t *dip, struct cmdk *dkp);
96507c3241Smlf static void cmdk_destroy_obj(dev_info_t *dip, struct cmdk *dkp);
97507c3241Smlf static void cmdkmin(struct buf *bp);
98507c3241Smlf static int cmdkrw(dev_t dev, struct uio *uio, int flag);
99507c3241Smlf static int cmdkarw(dev_t dev, struct aio_req *aio, int flag);
100507c3241Smlf 
101507c3241Smlf /*
102507c3241Smlf  * Bad Block Handling Functions Prototypes
103507c3241Smlf  */
104507c3241Smlf static void cmdk_bbh_reopen(struct cmdk *dkp);
105507c3241Smlf static opaque_t cmdk_bbh_gethandle(opaque_t bbh_data, struct buf *bp);
106507c3241Smlf static bbh_cookie_t cmdk_bbh_htoc(opaque_t bbh_data, opaque_t handle);
107507c3241Smlf static void cmdk_bbh_freehandle(opaque_t bbh_data, opaque_t handle);
108507c3241Smlf static void cmdk_bbh_close(struct cmdk *dkp);
109507c3241Smlf static void cmdk_bbh_setalts_idx(struct cmdk *dkp);
110507c3241Smlf static int cmdk_bbh_bsearch(struct alts_ent *buf, int cnt, daddr32_t key);
111507c3241Smlf 
112507c3241Smlf static struct bbh_objops cmdk_bbh_ops = {
113507c3241Smlf 	nulldev,
114507c3241Smlf 	nulldev,
115507c3241Smlf 	cmdk_bbh_gethandle,
116507c3241Smlf 	cmdk_bbh_htoc,
117507c3241Smlf 	cmdk_bbh_freehandle,
118507c3241Smlf 	0, 0
119507c3241Smlf };
120507c3241Smlf 
121507c3241Smlf static int cmdkopen(dev_t *dev_p, int flag, int otyp, cred_t *credp);
122507c3241Smlf static int cmdkclose(dev_t dev, int flag, int otyp, cred_t *credp);
123507c3241Smlf static int cmdkstrategy(struct buf *bp);
124507c3241Smlf static int cmdkdump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk);
125507c3241Smlf static int cmdkioctl(dev_t, int, intptr_t, int, cred_t *, int *);
126507c3241Smlf static int cmdkread(dev_t dev, struct uio *uio, cred_t *credp);
127507c3241Smlf static int cmdkwrite(dev_t dev, struct uio *uio, cred_t *credp);
128507c3241Smlf static int cmdk_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
129507c3241Smlf     int mod_flags, char *name, caddr_t valuep, int *lengthp);
130507c3241Smlf static int cmdkaread(dev_t dev, struct aio_req *aio, cred_t *credp);
131507c3241Smlf static int cmdkawrite(dev_t dev, struct aio_req *aio, cred_t *credp);
132507c3241Smlf 
133507c3241Smlf /*
134507c3241Smlf  * Device driver ops vector
135507c3241Smlf  */
136507c3241Smlf 
137507c3241Smlf static struct cb_ops cmdk_cb_ops = {
138507c3241Smlf 	cmdkopen, 		/* open */
139507c3241Smlf 	cmdkclose, 		/* close */
140507c3241Smlf 	cmdkstrategy, 		/* strategy */
141507c3241Smlf 	nodev, 			/* print */
142507c3241Smlf 	cmdkdump, 		/* dump */
143507c3241Smlf 	cmdkread, 		/* read */
144507c3241Smlf 	cmdkwrite, 		/* write */
145507c3241Smlf 	cmdkioctl, 		/* ioctl */
146507c3241Smlf 	nodev, 			/* devmap */
147507c3241Smlf 	nodev, 			/* mmap */
148507c3241Smlf 	nodev, 			/* segmap */
149507c3241Smlf 	nochpoll, 		/* poll */
150507c3241Smlf 	cmdk_prop_op, 		/* cb_prop_op */
151507c3241Smlf 	0, 			/* streamtab  */
152507c3241Smlf 	D_64BIT | D_MP | D_NEW,	/* Driver comaptibility flag */
153507c3241Smlf 	CB_REV,			/* cb_rev */
154507c3241Smlf 	cmdkaread,		/* async read */
155507c3241Smlf 	cmdkawrite		/* async write */
156507c3241Smlf };
157507c3241Smlf 
158507c3241Smlf static int cmdkinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
159507c3241Smlf     void **result);
160507c3241Smlf static int cmdkprobe(dev_info_t *dip);
161507c3241Smlf static int cmdkattach(dev_info_t *dip, ddi_attach_cmd_t cmd);
162507c3241Smlf static int cmdkdetach(dev_info_t *dip, ddi_detach_cmd_t cmd);
163507c3241Smlf 
1642df1fe9cSrandyf static void cmdk_setup_pm(dev_info_t *dip, struct cmdk *dkp);
1652df1fe9cSrandyf static int cmdkresume(dev_info_t *dip);
1662df1fe9cSrandyf static int cmdksuspend(dev_info_t *dip);
1672df1fe9cSrandyf static int cmdkpower(dev_info_t *dip, int component, int level);
1682df1fe9cSrandyf 
169507c3241Smlf struct dev_ops cmdk_ops = {
170507c3241Smlf 	DEVO_REV, 		/* devo_rev, */
171507c3241Smlf 	0, 			/* refcnt  */
172507c3241Smlf 	cmdkinfo,		/* info */
173507c3241Smlf 	nulldev, 		/* identify */
174507c3241Smlf 	cmdkprobe, 		/* probe */
175507c3241Smlf 	cmdkattach, 		/* attach */
176507c3241Smlf 	cmdkdetach,		/* detach */
177507c3241Smlf 	nodev, 			/* reset */
178507c3241Smlf 	&cmdk_cb_ops, 		/* driver operations */
1792df1fe9cSrandyf 	(struct bus_ops *)0,	/* bus operations */
18019397407SSherry Moore 	cmdkpower,		/* power */
18119397407SSherry Moore 	ddi_quiesce_not_needed,	/* quiesce */
182507c3241Smlf };
183507c3241Smlf 
184507c3241Smlf /*
185507c3241Smlf  * This is the loadable module wrapper.
186507c3241Smlf  */
187507c3241Smlf #include <sys/modctl.h>
188507c3241Smlf 
1897f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER
190507c3241Smlf static struct modldrv modldrv = {
191507c3241Smlf 	&mod_driverops,		/* Type of module. This one is a driver */
192613b2871SRichard Bean 	"Common Direct Access Disk",
193507c3241Smlf 	&cmdk_ops,				/* driver ops 		*/
194507c3241Smlf };
195507c3241Smlf 
196507c3241Smlf static struct modlinkage modlinkage = {
197507c3241Smlf 	MODREV_1, (void *)&modldrv, NULL
198507c3241Smlf };
199507c3241Smlf 
2007f0b8309SEdward Pilatowicz 
2017f0b8309SEdward Pilatowicz #else /* XPV_HVM_DRIVER */
2027f0b8309SEdward Pilatowicz static struct modlmisc modlmisc = {
2037f0b8309SEdward Pilatowicz 	&mod_miscops,		/* Type of module. This one is a misc */
2047f0b8309SEdward Pilatowicz 	"HVM Common Direct Access Disk",
2057f0b8309SEdward Pilatowicz };
2067f0b8309SEdward Pilatowicz 
2077f0b8309SEdward Pilatowicz static struct modlinkage modlinkage = {
2087f0b8309SEdward Pilatowicz 	MODREV_1, (void *)&modlmisc, NULL
2097f0b8309SEdward Pilatowicz };
2107f0b8309SEdward Pilatowicz 
2117f0b8309SEdward Pilatowicz #endif /* XPV_HVM_DRIVER */
2127f0b8309SEdward Pilatowicz 
213507c3241Smlf /* Function prototypes for cmlb callbacks */
214507c3241Smlf 
215507c3241Smlf static int cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr,
216e8fb11a1Sshidokht     diskaddr_t start, size_t length, void *tg_cookie);
217e8fb11a1Sshidokht 
218e8fb11a1Sshidokht static int cmdk_lb_getinfo(dev_info_t *dip, int cmd,  void *arg,
219e8fb11a1Sshidokht     void *tg_cookie);
220507c3241Smlf 
221507c3241Smlf static void cmdk_devid_setup(struct cmdk *dkp);
222507c3241Smlf static int cmdk_devid_modser(struct cmdk *dkp);
223507c3241Smlf static int cmdk_get_modser(struct cmdk *dkp, int ioccmd, char *buf, int len);
224507c3241Smlf static int cmdk_devid_fabricate(struct cmdk *dkp);
225507c3241Smlf static int cmdk_devid_read(struct cmdk *dkp);
226507c3241Smlf 
227507c3241Smlf static cmlb_tg_ops_t cmdk_lb_ops = {
228e8fb11a1Sshidokht 	TG_DK_OPS_VERSION_1,
229507c3241Smlf 	cmdk_lb_rdwr,
230e8fb11a1Sshidokht 	cmdk_lb_getinfo
231507c3241Smlf };
232507c3241Smlf 
23306bbe1e0Sedp static boolean_t
23406bbe1e0Sedp cmdk_isopen(struct cmdk *dkp, dev_t dev)
23506bbe1e0Sedp {
23606bbe1e0Sedp 	int		part, otyp;
23706bbe1e0Sedp 	ulong_t		partbit;
23806bbe1e0Sedp 
23906bbe1e0Sedp 	ASSERT(MUTEX_HELD((&dkp->dk_mutex)));
24006bbe1e0Sedp 
24106bbe1e0Sedp 	part = CMDKPART(dev);
24206bbe1e0Sedp 	partbit = 1 << part;
24306bbe1e0Sedp 
24406bbe1e0Sedp 	/* account for close */
24506bbe1e0Sedp 	if (dkp->dk_open_lyr[part] != 0)
24606bbe1e0Sedp 		return (B_TRUE);
24706bbe1e0Sedp 	for (otyp = 0; otyp < OTYPCNT; otyp++)
24806bbe1e0Sedp 		if (dkp->dk_open_reg[otyp] & partbit)
24906bbe1e0Sedp 			return (B_TRUE);
25006bbe1e0Sedp 	return (B_FALSE);
25106bbe1e0Sedp }
25206bbe1e0Sedp 
253507c3241Smlf int
254507c3241Smlf _init(void)
255507c3241Smlf {
256507c3241Smlf 	int 	rval;
257507c3241Smlf 
2587f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER
259507c3241Smlf 	if (rval = ddi_soft_state_init(&cmdk_state, sizeof (struct cmdk), 7))
260507c3241Smlf 		return (rval);
2617f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */
262507c3241Smlf 
263507c3241Smlf 	mutex_init(&cmdk_attach_mutex, NULL, MUTEX_DRIVER, NULL);
264507c3241Smlf 	if ((rval = mod_install(&modlinkage)) != 0) {
265507c3241Smlf 		mutex_destroy(&cmdk_attach_mutex);
2667f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER
267507c3241Smlf 		ddi_soft_state_fini(&cmdk_state);
2687f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */
269507c3241Smlf 	}
270507c3241Smlf 	return (rval);
271507c3241Smlf }
272507c3241Smlf 
273507c3241Smlf int
274507c3241Smlf _fini(void)
275507c3241Smlf {
276507c3241Smlf 	return (EBUSY);
277507c3241Smlf }
278507c3241Smlf 
279507c3241Smlf int
280507c3241Smlf _info(struct modinfo *modinfop)
281507c3241Smlf {
282507c3241Smlf 	return (mod_info(&modlinkage, modinfop));
283507c3241Smlf }
284507c3241Smlf 
285507c3241Smlf /*
286507c3241Smlf  * Autoconfiguration Routines
287507c3241Smlf  */
288507c3241Smlf static int
289507c3241Smlf cmdkprobe(dev_info_t *dip)
290507c3241Smlf {
291507c3241Smlf 	int 	instance;
292507c3241Smlf 	int	status;
293507c3241Smlf 	struct	cmdk	*dkp;
294507c3241Smlf 
295507c3241Smlf 	instance = ddi_get_instance(dip);
296507c3241Smlf 
2977f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER
298507c3241Smlf 	if (ddi_get_soft_state(cmdk_state, instance))
299507c3241Smlf 		return (DDI_PROBE_PARTIAL);
300507c3241Smlf 
3017f0b8309SEdward Pilatowicz 	if (ddi_soft_state_zalloc(cmdk_state, instance) != DDI_SUCCESS)
3027f0b8309SEdward Pilatowicz 		return (DDI_PROBE_PARTIAL);
3037f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */
3047f0b8309SEdward Pilatowicz 
3057f0b8309SEdward Pilatowicz 	if ((dkp = ddi_get_soft_state(cmdk_state, instance)) == NULL)
306507c3241Smlf 		return (DDI_PROBE_PARTIAL);
307507c3241Smlf 
308507c3241Smlf 	mutex_init(&dkp->dk_mutex, NULL, MUTEX_DRIVER, NULL);
309507c3241Smlf 	rw_init(&dkp->dk_bbh_mutex, NULL, RW_DRIVER, NULL);
310507c3241Smlf 	dkp->dk_dip = dip;
311507c3241Smlf 	mutex_enter(&dkp->dk_mutex);
312507c3241Smlf 
313507c3241Smlf 	dkp->dk_dev = makedevice(ddi_driver_major(dip),
314507c3241Smlf 	    ddi_get_instance(dip) << CMDK_UNITSHF);
315507c3241Smlf 
316507c3241Smlf 	/* linkage to dadk and strategy */
317507c3241Smlf 	if (cmdk_create_obj(dip, dkp) != DDI_SUCCESS) {
318507c3241Smlf 		mutex_exit(&dkp->dk_mutex);
319507c3241Smlf 		mutex_destroy(&dkp->dk_mutex);
320507c3241Smlf 		rw_destroy(&dkp->dk_bbh_mutex);
3217f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER
322507c3241Smlf 		ddi_soft_state_free(cmdk_state, instance);
3237f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */
324507c3241Smlf 		return (DDI_PROBE_PARTIAL);
325507c3241Smlf 	}
326507c3241Smlf 
327507c3241Smlf 	status = dadk_probe(DKTP_DATA, KM_NOSLEEP);
328507c3241Smlf 	if (status != DDI_PROBE_SUCCESS) {
329507c3241Smlf 		cmdk_destroy_obj(dip, dkp);	/* dadk/strategy linkage  */
330507c3241Smlf 		mutex_exit(&dkp->dk_mutex);
331507c3241Smlf 		mutex_destroy(&dkp->dk_mutex);
332507c3241Smlf 		rw_destroy(&dkp->dk_bbh_mutex);
3337f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER
334507c3241Smlf 		ddi_soft_state_free(cmdk_state, instance);
3357f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */
336507c3241Smlf 		return (status);
337507c3241Smlf 	}
338507c3241Smlf 
339507c3241Smlf 	mutex_exit(&dkp->dk_mutex);
340507c3241Smlf #ifdef CMDK_DEBUG
341507c3241Smlf 	if (cmdk_debug & DENT)
342507c3241Smlf 		PRF("cmdkprobe: instance= %d name= `%s`\n",
343507c3241Smlf 		    instance, ddi_get_name_addr(dip));
344507c3241Smlf #endif
345507c3241Smlf 	return (status);
346507c3241Smlf }
347507c3241Smlf 
348507c3241Smlf static int
349507c3241Smlf cmdkattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
350507c3241Smlf {
351507c3241Smlf 	int 		instance;
352507c3241Smlf 	struct		cmdk *dkp;
353507c3241Smlf 	char 		*node_type;
354507c3241Smlf 
3552df1fe9cSrandyf 	switch (cmd) {
3562df1fe9cSrandyf 	case DDI_ATTACH:
3572df1fe9cSrandyf 		break;
3582df1fe9cSrandyf 	case DDI_RESUME:
3592df1fe9cSrandyf 		return (cmdkresume(dip));
3602df1fe9cSrandyf 	default:
361507c3241Smlf 		return (DDI_FAILURE);
3622df1fe9cSrandyf 	}
363507c3241Smlf 
364507c3241Smlf 	instance = ddi_get_instance(dip);
365507c3241Smlf 	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
366507c3241Smlf 		return (DDI_FAILURE);
367507c3241Smlf 
3682df1fe9cSrandyf 	dkp->dk_pm_level = CMDK_SPINDLE_UNINIT;
3692df1fe9cSrandyf 	mutex_init(&dkp->dk_mutex, NULL, MUTEX_DRIVER, NULL);
3702df1fe9cSrandyf 
371507c3241Smlf 	mutex_enter(&dkp->dk_mutex);
372507c3241Smlf 
373507c3241Smlf 	/* dadk_attach is an empty function that only returns SUCCESS */
374507c3241Smlf 	(void) dadk_attach(DKTP_DATA);
375507c3241Smlf 
376507c3241Smlf 	node_type = (DKTP_EXT->tg_nodetype);
377507c3241Smlf 
378507c3241Smlf 	/*
379507c3241Smlf 	 * this open allows cmlb to read the device
380507c3241Smlf 	 * and determine the label types
381507c3241Smlf 	 * so that cmlb can create minor nodes for device
382507c3241Smlf 	 */
383507c3241Smlf 
384507c3241Smlf 	/* open the target disk	 */
385507c3241Smlf 	if (dadk_open(DKTP_DATA, 0) != DDI_SUCCESS)
386507c3241Smlf 		goto fail2;
387507c3241Smlf 
388342440ecSPrasad Singamsetty #ifdef _ILP32
389342440ecSPrasad Singamsetty 	{
390342440ecSPrasad Singamsetty 		struct  tgdk_geom phyg;
391342440ecSPrasad Singamsetty 		(void) dadk_getphygeom(DKTP_DATA, &phyg);
392342440ecSPrasad Singamsetty 		if ((phyg.g_cap - 1) > DK_MAX_BLOCKS) {
393342440ecSPrasad Singamsetty 			(void) dadk_close(DKTP_DATA);
394342440ecSPrasad Singamsetty 			goto fail2;
395342440ecSPrasad Singamsetty 		}
396342440ecSPrasad Singamsetty 	}
397342440ecSPrasad Singamsetty #endif
398342440ecSPrasad Singamsetty 
399342440ecSPrasad Singamsetty 
400507c3241Smlf 	/* mark as having opened target */
401507c3241Smlf 	dkp->dk_flag |= CMDK_TGDK_OPEN;
402507c3241Smlf 
403507c3241Smlf 	cmlb_alloc_handle((cmlb_handle_t *)&dkp->dk_cmlbhandle);
404507c3241Smlf 
405507c3241Smlf 	if (cmlb_attach(dip,
406507c3241Smlf 	    &cmdk_lb_ops,
407507c3241Smlf 	    DTYPE_DIRECT,		/* device_type */
4087f0b8309SEdward Pilatowicz 	    B_FALSE,			/* removable */
4097f0b8309SEdward Pilatowicz 	    B_FALSE,			/* hot pluggable XXX */
410507c3241Smlf 	    node_type,
411507c3241Smlf 	    CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT,	/* alter_behaviour */
412e8fb11a1Sshidokht 	    dkp->dk_cmlbhandle,
413e8fb11a1Sshidokht 	    0) != 0)
414507c3241Smlf 		goto fail1;
415507c3241Smlf 
416507c3241Smlf 	/* Calling validate will create minor nodes according to disk label */
417e8fb11a1Sshidokht 	(void) cmlb_validate(dkp->dk_cmlbhandle, 0, 0);
418507c3241Smlf 
419507c3241Smlf 	/* set bbh (Bad Block Handling) */
420507c3241Smlf 	cmdk_bbh_reopen(dkp);
421507c3241Smlf 
422507c3241Smlf 	/* setup devid string */
423507c3241Smlf 	cmdk_devid_setup(dkp);
424507c3241Smlf 
425507c3241Smlf 	mutex_enter(&cmdk_attach_mutex);
426507c3241Smlf 	if (instance > cmdk_max_instance)
427507c3241Smlf 		cmdk_max_instance = instance;
428507c3241Smlf 	mutex_exit(&cmdk_attach_mutex);
429507c3241Smlf 
430507c3241Smlf 	mutex_exit(&dkp->dk_mutex);
431507c3241Smlf 
432507c3241Smlf 	/*
433507c3241Smlf 	 * Add a zero-length attribute to tell the world we support
434507c3241Smlf 	 * kernel ioctls (for layered drivers)
435507c3241Smlf 	 */
436507c3241Smlf 	(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
437507c3241Smlf 	    DDI_KERNEL_IOCTL, NULL, 0);
438507c3241Smlf 	ddi_report_dev(dip);
439507c3241Smlf 
4402df1fe9cSrandyf 	/*
4412df1fe9cSrandyf 	 * Initialize power management
4422df1fe9cSrandyf 	 */
4432df1fe9cSrandyf 	mutex_init(&dkp->dk_pm_mutex, NULL, MUTEX_DRIVER, NULL);
4442df1fe9cSrandyf 	cv_init(&dkp->dk_suspend_cv,   NULL, CV_DRIVER, NULL);
4452df1fe9cSrandyf 	cmdk_setup_pm(dip, dkp);
4462df1fe9cSrandyf 
447507c3241Smlf 	return (DDI_SUCCESS);
448507c3241Smlf 
449507c3241Smlf fail1:
450507c3241Smlf 	cmlb_free_handle(&dkp->dk_cmlbhandle);
451507c3241Smlf 	(void) dadk_close(DKTP_DATA);
452507c3241Smlf fail2:
453507c3241Smlf 	cmdk_destroy_obj(dip, dkp);
454507c3241Smlf 	rw_destroy(&dkp->dk_bbh_mutex);
455507c3241Smlf 	mutex_exit(&dkp->dk_mutex);
456507c3241Smlf 	mutex_destroy(&dkp->dk_mutex);
4577f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER
458507c3241Smlf 	ddi_soft_state_free(cmdk_state, instance);
4597f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */
460507c3241Smlf 	return (DDI_FAILURE);
461507c3241Smlf }
462507c3241Smlf 
463507c3241Smlf 
464507c3241Smlf static int
465507c3241Smlf cmdkdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
466507c3241Smlf {
467507c3241Smlf 	struct cmdk	*dkp;
468507c3241Smlf 	int 		instance;
469507c3241Smlf 	int		max_instance;
470507c3241Smlf 
4712df1fe9cSrandyf 	switch (cmd) {
4722df1fe9cSrandyf 	case DDI_DETACH:
4732df1fe9cSrandyf 		/* return (DDI_FAILURE); */
4742df1fe9cSrandyf 		break;
4752df1fe9cSrandyf 	case DDI_SUSPEND:
4762df1fe9cSrandyf 		return (cmdksuspend(dip));
4772df1fe9cSrandyf 	default:
478507c3241Smlf #ifdef CMDK_DEBUG
479507c3241Smlf 		if (cmdk_debug & DIO) {
480507c3241Smlf 			PRF("cmdkdetach: cmd = %d unknown\n", cmd);
481507c3241Smlf 		}
482507c3241Smlf #endif
483507c3241Smlf 		return (DDI_FAILURE);
484507c3241Smlf 	}
485507c3241Smlf 
486507c3241Smlf 	mutex_enter(&cmdk_attach_mutex);
487507c3241Smlf 	max_instance = cmdk_max_instance;
488507c3241Smlf 	mutex_exit(&cmdk_attach_mutex);
489507c3241Smlf 
490507c3241Smlf 	/* check if any instance of driver is open */
491507c3241Smlf 	for (instance = 0; instance < max_instance; instance++) {
492507c3241Smlf 		dkp = ddi_get_soft_state(cmdk_state, instance);
493507c3241Smlf 		if (!dkp)
494507c3241Smlf 			continue;
495507c3241Smlf 		if (dkp->dk_flag & CMDK_OPEN)
496507c3241Smlf 			return (DDI_FAILURE);
497507c3241Smlf 	}
498507c3241Smlf 
499507c3241Smlf 	instance = ddi_get_instance(dip);
500507c3241Smlf 	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
501507c3241Smlf 		return (DDI_SUCCESS);
502507c3241Smlf 
503507c3241Smlf 	mutex_enter(&dkp->dk_mutex);
504507c3241Smlf 
505507c3241Smlf 	/*
506507c3241Smlf 	 * The cmdk_part_info call at the end of cmdkattach may have
507507c3241Smlf 	 * caused cmdk_reopen to do a TGDK_OPEN, make sure we close on
508507c3241Smlf 	 * detach for case when cmdkopen/cmdkclose never occurs.
509507c3241Smlf 	 */
510507c3241Smlf 	if (dkp->dk_flag & CMDK_TGDK_OPEN) {
511507c3241Smlf 		dkp->dk_flag &= ~CMDK_TGDK_OPEN;
512507c3241Smlf 		(void) dadk_close(DKTP_DATA);
513507c3241Smlf 	}
514507c3241Smlf 
515e8fb11a1Sshidokht 	cmlb_detach(dkp->dk_cmlbhandle, 0);
516507c3241Smlf 	cmlb_free_handle(&dkp->dk_cmlbhandle);
517507c3241Smlf 	ddi_prop_remove_all(dip);
518507c3241Smlf 
519507c3241Smlf 	cmdk_destroy_obj(dip, dkp);	/* dadk/strategy linkage  */
5208b6b46faSzhongyan gu - Sun Microsystems - Beijing China 
5218b6b46faSzhongyan gu - Sun Microsystems - Beijing China 	/*
5228b6b46faSzhongyan gu - Sun Microsystems - Beijing China 	 * free the devid structure if allocated before
5238b6b46faSzhongyan gu - Sun Microsystems - Beijing China 	 */
5248b6b46faSzhongyan gu - Sun Microsystems - Beijing China 	if (dkp->dk_devid) {
5258b6b46faSzhongyan gu - Sun Microsystems - Beijing China 		ddi_devid_free(dkp->dk_devid);
5268b6b46faSzhongyan gu - Sun Microsystems - Beijing China 		dkp->dk_devid = NULL;
5278b6b46faSzhongyan gu - Sun Microsystems - Beijing China 	}
5288b6b46faSzhongyan gu - Sun Microsystems - Beijing China 
529507c3241Smlf 	mutex_exit(&dkp->dk_mutex);
530507c3241Smlf 	mutex_destroy(&dkp->dk_mutex);
531507c3241Smlf 	rw_destroy(&dkp->dk_bbh_mutex);
5322df1fe9cSrandyf 	mutex_destroy(&dkp->dk_pm_mutex);
5332df1fe9cSrandyf 	cv_destroy(&dkp->dk_suspend_cv);
5347f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER
535507c3241Smlf 	ddi_soft_state_free(cmdk_state, instance);
5367f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */
537507c3241Smlf 
538507c3241Smlf 	return (DDI_SUCCESS);
539507c3241Smlf }
540507c3241Smlf 
541507c3241Smlf static int
542507c3241Smlf cmdkinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
543507c3241Smlf {
544507c3241Smlf 	dev_t		dev = (dev_t)arg;
545507c3241Smlf 	int 		instance;
546507c3241Smlf 	struct	cmdk	*dkp;
547507c3241Smlf 
548507c3241Smlf #ifdef lint
549507c3241Smlf 	dip = dip;	/* no one ever uses this */
550507c3241Smlf #endif
551507c3241Smlf #ifdef CMDK_DEBUG
552507c3241Smlf 	if (cmdk_debug & DENT)
553507c3241Smlf 		PRF("cmdkinfo: call\n");
554507c3241Smlf #endif
555507c3241Smlf 	instance = CMDKUNIT(dev);
556507c3241Smlf 
557507c3241Smlf 	switch (infocmd) {
558507c3241Smlf 		case DDI_INFO_DEVT2DEVINFO:
559507c3241Smlf 			if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
560507c3241Smlf 				return (DDI_FAILURE);
561507c3241Smlf 			*result = (void *) dkp->dk_dip;
562507c3241Smlf 			break;
563507c3241Smlf 		case DDI_INFO_DEVT2INSTANCE:
564507c3241Smlf 			*result = (void *)(intptr_t)instance;
565507c3241Smlf 			break;
566507c3241Smlf 		default:
567507c3241Smlf 			return (DDI_FAILURE);
568507c3241Smlf 	}
569507c3241Smlf 	return (DDI_SUCCESS);
570507c3241Smlf }
571507c3241Smlf 
5722df1fe9cSrandyf /*
5732df1fe9cSrandyf  * Initialize the power management components
5742df1fe9cSrandyf  */
5752df1fe9cSrandyf static void
5762df1fe9cSrandyf cmdk_setup_pm(dev_info_t *dip, struct cmdk *dkp)
5772df1fe9cSrandyf {
5782df1fe9cSrandyf 	char *pm_comp[] = { "NAME=cmdk", "0=off", "1=on", NULL };
5792df1fe9cSrandyf 
5802df1fe9cSrandyf 	/*
5812df1fe9cSrandyf 	 * Since the cmdk device does not the 'reg' property,
5822df1fe9cSrandyf 	 * cpr will not call its DDI_SUSPEND/DDI_RESUME entries.
5832df1fe9cSrandyf 	 * The following code is to tell cpr that this device
5842df1fe9cSrandyf 	 * DOES need to be suspended and resumed.
5852df1fe9cSrandyf 	 */
5862df1fe9cSrandyf 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
5872df1fe9cSrandyf 	    "pm-hardware-state", "needs-suspend-resume");
5882df1fe9cSrandyf 
5892df1fe9cSrandyf 	if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
5902df1fe9cSrandyf 	    "pm-components", pm_comp, 3) == DDI_PROP_SUCCESS) {
5912df1fe9cSrandyf 		if (pm_raise_power(dip, 0, CMDK_SPINDLE_ON) == DDI_SUCCESS) {
5922df1fe9cSrandyf 			mutex_enter(&dkp->dk_pm_mutex);
5932df1fe9cSrandyf 			dkp->dk_pm_level = CMDK_SPINDLE_ON;
5942df1fe9cSrandyf 			dkp->dk_pm_is_enabled = 1;
5952df1fe9cSrandyf 			mutex_exit(&dkp->dk_pm_mutex);
5962df1fe9cSrandyf 		} else {
5972df1fe9cSrandyf 			mutex_enter(&dkp->dk_pm_mutex);
5982df1fe9cSrandyf 			dkp->dk_pm_level = CMDK_SPINDLE_OFF;
5992df1fe9cSrandyf 			dkp->dk_pm_is_enabled = 0;
6002df1fe9cSrandyf 			mutex_exit(&dkp->dk_pm_mutex);
6012df1fe9cSrandyf 		}
6022df1fe9cSrandyf 	} else {
6032df1fe9cSrandyf 		mutex_enter(&dkp->dk_pm_mutex);
6042df1fe9cSrandyf 		dkp->dk_pm_level = CMDK_SPINDLE_UNINIT;
6052df1fe9cSrandyf 		dkp->dk_pm_is_enabled = 0;
6062df1fe9cSrandyf 		mutex_exit(&dkp->dk_pm_mutex);
6072df1fe9cSrandyf 	}
6082df1fe9cSrandyf }
6092df1fe9cSrandyf 
6102df1fe9cSrandyf /*
6112df1fe9cSrandyf  * suspend routine, it will be run when get the command
6122df1fe9cSrandyf  * DDI_SUSPEND at detach(9E) from system power management
6132df1fe9cSrandyf  */
6142df1fe9cSrandyf static int
6152df1fe9cSrandyf cmdksuspend(dev_info_t *dip)
6162df1fe9cSrandyf {
6172df1fe9cSrandyf 	struct cmdk	*dkp;
6182df1fe9cSrandyf 	int		instance;
6192df1fe9cSrandyf 	clock_t		count = 0;
6202df1fe9cSrandyf 
6212df1fe9cSrandyf 	instance = ddi_get_instance(dip);
6222df1fe9cSrandyf 	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
6232df1fe9cSrandyf 		return (DDI_FAILURE);
6242df1fe9cSrandyf 	mutex_enter(&dkp->dk_mutex);
6252df1fe9cSrandyf 	if (dkp->dk_flag & CMDK_SUSPEND) {
6262df1fe9cSrandyf 		mutex_exit(&dkp->dk_mutex);
6272df1fe9cSrandyf 		return (DDI_SUCCESS);
6282df1fe9cSrandyf 	}
6292df1fe9cSrandyf 	dkp->dk_flag |= CMDK_SUSPEND;
6302df1fe9cSrandyf 
6312df1fe9cSrandyf 	/* need to wait a while */
6322df1fe9cSrandyf 	while (dadk_getcmds(DKTP_DATA) != 0) {
6332df1fe9cSrandyf 		delay(drv_usectohz(1000000));
6342df1fe9cSrandyf 		if (count > 60) {
6352df1fe9cSrandyf 			dkp->dk_flag &= ~CMDK_SUSPEND;
6362df1fe9cSrandyf 			cv_broadcast(&dkp->dk_suspend_cv);
6372df1fe9cSrandyf 			mutex_exit(&dkp->dk_mutex);
6382df1fe9cSrandyf 			return (DDI_FAILURE);
6392df1fe9cSrandyf 		}
6402df1fe9cSrandyf 		count++;
6412df1fe9cSrandyf 	}
6422df1fe9cSrandyf 	mutex_exit(&dkp->dk_mutex);
6432df1fe9cSrandyf 	return (DDI_SUCCESS);
6442df1fe9cSrandyf }
6452df1fe9cSrandyf 
6462df1fe9cSrandyf /*
6472df1fe9cSrandyf  * resume routine, it will be run when get the command
6482df1fe9cSrandyf  * DDI_RESUME at attach(9E) from system power management
6492df1fe9cSrandyf  */
6502df1fe9cSrandyf static int
6512df1fe9cSrandyf cmdkresume(dev_info_t *dip)
6522df1fe9cSrandyf {
6532df1fe9cSrandyf 	struct cmdk	*dkp;
6542df1fe9cSrandyf 	int		instance;
6552df1fe9cSrandyf 
6562df1fe9cSrandyf 	instance = ddi_get_instance(dip);
6572df1fe9cSrandyf 	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
6582df1fe9cSrandyf 		return (DDI_FAILURE);
6592df1fe9cSrandyf 	mutex_enter(&dkp->dk_mutex);
6602df1fe9cSrandyf 	if (!(dkp->dk_flag & CMDK_SUSPEND)) {
6612df1fe9cSrandyf 		mutex_exit(&dkp->dk_mutex);
6622df1fe9cSrandyf 		return (DDI_FAILURE);
6632df1fe9cSrandyf 	}
6642df1fe9cSrandyf 	dkp->dk_pm_level = CMDK_SPINDLE_ON;
6652df1fe9cSrandyf 	dkp->dk_flag &= ~CMDK_SUSPEND;
6662df1fe9cSrandyf 	cv_broadcast(&dkp->dk_suspend_cv);
6672df1fe9cSrandyf 	mutex_exit(&dkp->dk_mutex);
6682df1fe9cSrandyf 	return (DDI_SUCCESS);
6692df1fe9cSrandyf 
6702df1fe9cSrandyf }
6712df1fe9cSrandyf 
6722df1fe9cSrandyf /*
6732df1fe9cSrandyf  * power management entry point, it was used to
6742df1fe9cSrandyf  * change power management component.
6752df1fe9cSrandyf  * Actually, the real hard drive suspend/resume
6762df1fe9cSrandyf  * was handled in ata, so this function is not
6772df1fe9cSrandyf  * doing any real work other than verifying that
6782df1fe9cSrandyf  * the disk is idle.
6792df1fe9cSrandyf  */
6802df1fe9cSrandyf static int
6812df1fe9cSrandyf cmdkpower(dev_info_t *dip, int component, int level)
6822df1fe9cSrandyf {
6832df1fe9cSrandyf 	struct cmdk	*dkp;
6842df1fe9cSrandyf 	int		instance;
6852df1fe9cSrandyf 
6862df1fe9cSrandyf 	instance = ddi_get_instance(dip);
6872df1fe9cSrandyf 	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) ||
6882df1fe9cSrandyf 	    component != 0 || level > CMDK_SPINDLE_ON ||
6892df1fe9cSrandyf 	    level < CMDK_SPINDLE_OFF) {
6902df1fe9cSrandyf 		return (DDI_FAILURE);
6912df1fe9cSrandyf 	}
6922df1fe9cSrandyf 
6932df1fe9cSrandyf 	mutex_enter(&dkp->dk_pm_mutex);
6942df1fe9cSrandyf 	if (dkp->dk_pm_is_enabled && dkp->dk_pm_level == level) {
6952df1fe9cSrandyf 		mutex_exit(&dkp->dk_pm_mutex);
6962df1fe9cSrandyf 		return (DDI_SUCCESS);
6972df1fe9cSrandyf 	}
6982df1fe9cSrandyf 	mutex_exit(&dkp->dk_pm_mutex);
6992df1fe9cSrandyf 
7002df1fe9cSrandyf 	if ((level == CMDK_SPINDLE_OFF) &&
7012df1fe9cSrandyf 	    (dadk_getcmds(DKTP_DATA) != 0)) {
7022df1fe9cSrandyf 		return (DDI_FAILURE);
7032df1fe9cSrandyf 	}
7042df1fe9cSrandyf 
7052df1fe9cSrandyf 	mutex_enter(&dkp->dk_pm_mutex);
7062df1fe9cSrandyf 	dkp->dk_pm_level = level;
7072df1fe9cSrandyf 	mutex_exit(&dkp->dk_pm_mutex);
7082df1fe9cSrandyf 	return (DDI_SUCCESS);
7092df1fe9cSrandyf }
7102df1fe9cSrandyf 
711507c3241Smlf static int
712507c3241Smlf cmdk_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
713507c3241Smlf     char *name, caddr_t valuep, int *lengthp)
714507c3241Smlf {
715507c3241Smlf 	struct	cmdk	*dkp;
716507c3241Smlf 
717507c3241Smlf #ifdef CMDK_DEBUG
718507c3241Smlf 	if (cmdk_debug & DENT)
719507c3241Smlf 		PRF("cmdk_prop_op: call\n");
720507c3241Smlf #endif
721507c3241Smlf 
722507c3241Smlf 	dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip));
723b9ccdc5aScth 	if (dkp == NULL)
724b9ccdc5aScth 		return (ddi_prop_op(dev, dip, prop_op, mod_flags,
725507c3241Smlf 		    name, valuep, lengthp));
726b9ccdc5aScth 
727b9ccdc5aScth 	return (cmlb_prop_op(dkp->dk_cmlbhandle,
728b9ccdc5aScth 	    dev, dip, prop_op, mod_flags, name, valuep, lengthp,
729b9ccdc5aScth 	    CMDKPART(dev), NULL));
730507c3241Smlf }
731507c3241Smlf 
732507c3241Smlf /*
733507c3241Smlf  * dump routine
734507c3241Smlf  */
735507c3241Smlf static int
736507c3241Smlf cmdkdump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk)
737507c3241Smlf {
738507c3241Smlf 	int 		instance;
739507c3241Smlf 	struct	cmdk	*dkp;
740507c3241Smlf 	diskaddr_t	p_lblksrt;
741507c3241Smlf 	diskaddr_t	p_lblkcnt;
742507c3241Smlf 	struct	buf	local;
743507c3241Smlf 	struct	buf	*bp;
744507c3241Smlf 
745507c3241Smlf #ifdef CMDK_DEBUG
746507c3241Smlf 	if (cmdk_debug & DENT)
747507c3241Smlf 		PRF("cmdkdump: call\n");
748507c3241Smlf #endif
749507c3241Smlf 	instance = CMDKUNIT(dev);
750507c3241Smlf 	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) || (blkno < 0))
751507c3241Smlf 		return (ENXIO);
752507c3241Smlf 
753507c3241Smlf 	if (cmlb_partinfo(
754507c3241Smlf 	    dkp->dk_cmlbhandle,
755507c3241Smlf 	    CMDKPART(dev),
756507c3241Smlf 	    &p_lblkcnt,
757507c3241Smlf 	    &p_lblksrt,
758507c3241Smlf 	    NULL,
759e8fb11a1Sshidokht 	    NULL,
760e8fb11a1Sshidokht 	    0)) {
761507c3241Smlf 		return (ENXIO);
762507c3241Smlf 	}
763507c3241Smlf 
764507c3241Smlf 	if ((blkno+nblk) > p_lblkcnt)
765507c3241Smlf 		return (EINVAL);
766507c3241Smlf 
767507c3241Smlf 	cmdk_indump = 1;	/* Tell disk targets we are panic dumpping */
768507c3241Smlf 
769507c3241Smlf 	bp = &local;
770507c3241Smlf 	bzero(bp, sizeof (*bp));
771507c3241Smlf 	bp->b_flags = B_BUSY;
772507c3241Smlf 	bp->b_un.b_addr = addr;
773507c3241Smlf 	bp->b_bcount = nblk << SCTRSHFT;
774507c3241Smlf 	SET_BP_SEC(bp, ((ulong_t)(p_lblksrt + blkno)));
775507c3241Smlf 
776507c3241Smlf 	(void) dadk_dump(DKTP_DATA, bp);
777507c3241Smlf 	return (bp->b_error);
778507c3241Smlf }
779507c3241Smlf 
780507c3241Smlf /*
781507c3241Smlf  * Copy in the dadkio_rwcmd according to the user's data model.  If needed,
782507c3241Smlf  * convert it for our internal use.
783507c3241Smlf  */
784507c3241Smlf static int
785507c3241Smlf rwcmd_copyin(struct dadkio_rwcmd *rwcmdp, caddr_t inaddr, int flag)
786507c3241Smlf {
787507c3241Smlf 	switch (ddi_model_convert_from(flag)) {
788507c3241Smlf 		case DDI_MODEL_ILP32: {
789507c3241Smlf 			struct dadkio_rwcmd32 cmd32;
790507c3241Smlf 
791507c3241Smlf 			if (ddi_copyin(inaddr, &cmd32,
792507c3241Smlf 			    sizeof (struct dadkio_rwcmd32), flag)) {
793507c3241Smlf 				return (EFAULT);
794507c3241Smlf 			}
795507c3241Smlf 
796507c3241Smlf 			rwcmdp->cmd = cmd32.cmd;
797507c3241Smlf 			rwcmdp->flags = cmd32.flags;
798342440ecSPrasad Singamsetty 			rwcmdp->blkaddr = (blkaddr_t)cmd32.blkaddr;
799507c3241Smlf 			rwcmdp->buflen = cmd32.buflen;
800507c3241Smlf 			rwcmdp->bufaddr = (caddr_t)(intptr_t)cmd32.bufaddr;
801507c3241Smlf 			/*
802507c3241Smlf 			 * Note: we do not convert the 'status' field,
803507c3241Smlf 			 * as it should not contain valid data at this
804507c3241Smlf 			 * point.
805507c3241Smlf 			 */
806507c3241Smlf 			bzero(&rwcmdp->status, sizeof (rwcmdp->status));
807507c3241Smlf 			break;
808507c3241Smlf 		}
809507c3241Smlf 		case DDI_MODEL_NONE: {
810507c3241Smlf 			if (ddi_copyin(inaddr, rwcmdp,
811507c3241Smlf 			    sizeof (struct dadkio_rwcmd), flag)) {
812507c3241Smlf 				return (EFAULT);
813507c3241Smlf 			}
814507c3241Smlf 		}
815507c3241Smlf 	}
816507c3241Smlf 	return (0);
817507c3241Smlf }
818507c3241Smlf 
819507c3241Smlf /*
820507c3241Smlf  * If necessary, convert the internal rwcmdp and status to the appropriate
821507c3241Smlf  * data model and copy it out to the user.
822507c3241Smlf  */
823507c3241Smlf static int
824507c3241Smlf rwcmd_copyout(struct dadkio_rwcmd *rwcmdp, caddr_t outaddr, int flag)
825507c3241Smlf {
826507c3241Smlf 	switch (ddi_model_convert_from(flag)) {
827507c3241Smlf 		case DDI_MODEL_ILP32: {
828507c3241Smlf 			struct dadkio_rwcmd32 cmd32;
829507c3241Smlf 
830507c3241Smlf 			cmd32.cmd = rwcmdp->cmd;
831507c3241Smlf 			cmd32.flags = rwcmdp->flags;
832507c3241Smlf 			cmd32.blkaddr = rwcmdp->blkaddr;
833507c3241Smlf 			cmd32.buflen = rwcmdp->buflen;
834507c3241Smlf 			ASSERT64(((uintptr_t)rwcmdp->bufaddr >> 32) == 0);
835507c3241Smlf 			cmd32.bufaddr = (caddr32_t)(uintptr_t)rwcmdp->bufaddr;
836507c3241Smlf 
837507c3241Smlf 			cmd32.status.status = rwcmdp->status.status;
838507c3241Smlf 			cmd32.status.resid = rwcmdp->status.resid;
839507c3241Smlf 			cmd32.status.failed_blk_is_valid =
840507c3241Smlf 			    rwcmdp->status.failed_blk_is_valid;
841507c3241Smlf 			cmd32.status.failed_blk = rwcmdp->status.failed_blk;
842507c3241Smlf 			cmd32.status.fru_code_is_valid =
843507c3241Smlf 			    rwcmdp->status.fru_code_is_valid;
844507c3241Smlf 			cmd32.status.fru_code = rwcmdp->status.fru_code;
845507c3241Smlf 
846507c3241Smlf 			bcopy(rwcmdp->status.add_error_info,
847507c3241Smlf 			    cmd32.status.add_error_info, DADKIO_ERROR_INFO_LEN);
848507c3241Smlf 
849507c3241Smlf 			if (ddi_copyout(&cmd32, outaddr,
850507c3241Smlf 			    sizeof (struct dadkio_rwcmd32), flag))
851507c3241Smlf 				return (EFAULT);
852507c3241Smlf 			break;
853507c3241Smlf 		}
854507c3241Smlf 		case DDI_MODEL_NONE: {
855507c3241Smlf 			if (ddi_copyout(rwcmdp, outaddr,
856507c3241Smlf 			    sizeof (struct dadkio_rwcmd), flag))
857507c3241Smlf 			return (EFAULT);
858507c3241Smlf 		}
859507c3241Smlf 	}
860507c3241Smlf 	return (0);
861507c3241Smlf }
862507c3241Smlf 
863507c3241Smlf /*
864507c3241Smlf  * ioctl routine
865507c3241Smlf  */
866507c3241Smlf static int
867507c3241Smlf cmdkioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp)
868507c3241Smlf {
869507c3241Smlf 	int 		instance;
870507c3241Smlf 	struct scsi_device *devp;
871507c3241Smlf 	struct cmdk	*dkp;
872507c3241Smlf 	char 		data[NBPSCTR];
873507c3241Smlf 
874507c3241Smlf 	instance = CMDKUNIT(dev);
875507c3241Smlf 	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
876507c3241Smlf 		return (ENXIO);
877507c3241Smlf 
8782df1fe9cSrandyf 	mutex_enter(&dkp->dk_mutex);
8792df1fe9cSrandyf 	while (dkp->dk_flag & CMDK_SUSPEND) {
8802df1fe9cSrandyf 		cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
8812df1fe9cSrandyf 	}
8822df1fe9cSrandyf 	mutex_exit(&dkp->dk_mutex);
8832df1fe9cSrandyf 
884507c3241Smlf 	bzero(data, sizeof (data));
885507c3241Smlf 
886507c3241Smlf 	switch (cmd) {
887507c3241Smlf 
888507c3241Smlf 	case DKIOCGMEDIAINFO: {
889507c3241Smlf 		struct dk_minfo	media_info;
890507c3241Smlf 		struct  tgdk_geom phyg;
891507c3241Smlf 
892507c3241Smlf 		/* dadk_getphygeom always returns success */
893507c3241Smlf 		(void) dadk_getphygeom(DKTP_DATA, &phyg);
894507c3241Smlf 
895507c3241Smlf 		media_info.dki_lbsize = phyg.g_secsiz;
896507c3241Smlf 		media_info.dki_capacity = phyg.g_cap;
897507c3241Smlf 		media_info.dki_media_type = DK_FIXED_DISK;
898507c3241Smlf 
899507c3241Smlf 		if (ddi_copyout(&media_info, (void *)arg,
900507c3241Smlf 		    sizeof (struct dk_minfo), flag)) {
901507c3241Smlf 			return (EFAULT);
902507c3241Smlf 		} else {
903507c3241Smlf 			return (0);
904507c3241Smlf 		}
905507c3241Smlf 	}
906507c3241Smlf 
907507c3241Smlf 	case DKIOCINFO: {
908507c3241Smlf 		struct dk_cinfo *info = (struct dk_cinfo *)data;
909507c3241Smlf 
910507c3241Smlf 		/* controller information */
911507c3241Smlf 		info->dki_ctype = (DKTP_EXT->tg_ctype);
912507c3241Smlf 		info->dki_cnum = ddi_get_instance(ddi_get_parent(dkp->dk_dip));
913507c3241Smlf 		(void) strcpy(info->dki_cname,
914507c3241Smlf 		    ddi_get_name(ddi_get_parent(dkp->dk_dip)));
915507c3241Smlf 
916507c3241Smlf 		/* Unit Information */
917507c3241Smlf 		info->dki_unit = ddi_get_instance(dkp->dk_dip);
918507c3241Smlf 		devp = ddi_get_driver_private(dkp->dk_dip);
919507c3241Smlf 		info->dki_slave = (CMDEV_TARG(devp)<<3) | CMDEV_LUN(devp);
920507c3241Smlf 		(void) strcpy(info->dki_dname, ddi_driver_name(dkp->dk_dip));
921507c3241Smlf 		info->dki_flags = DKI_FMTVOL;
922507c3241Smlf 		info->dki_partition = CMDKPART(dev);
923507c3241Smlf 
924507c3241Smlf 		info->dki_maxtransfer = maxphys / DEV_BSIZE;
925507c3241Smlf 		info->dki_addr = 1;
926507c3241Smlf 		info->dki_space = 0;
927507c3241Smlf 		info->dki_prio = 0;
928507c3241Smlf 		info->dki_vec = 0;
929507c3241Smlf 
930507c3241Smlf 		if (ddi_copyout(data, (void *)arg, sizeof (*info), flag))
931507c3241Smlf 			return (EFAULT);
932507c3241Smlf 		else
933507c3241Smlf 			return (0);
934507c3241Smlf 	}
935507c3241Smlf 
936507c3241Smlf 	case DKIOCSTATE: {
937507c3241Smlf 		int	state;
938507c3241Smlf 		int	rval;
939507c3241Smlf 		diskaddr_t	p_lblksrt;
940507c3241Smlf 		diskaddr_t	p_lblkcnt;
941507c3241Smlf 
942507c3241Smlf 		if (ddi_copyin((void *)arg, &state, sizeof (int), flag))
943507c3241Smlf 			return (EFAULT);
944507c3241Smlf 
945507c3241Smlf 		/* dadk_check_media blocks until state changes */
946507c3241Smlf 		if (rval = dadk_check_media(DKTP_DATA, &state))
947507c3241Smlf 			return (rval);
948507c3241Smlf 
949507c3241Smlf 		if (state == DKIO_INSERTED) {
950507c3241Smlf 
951e8fb11a1Sshidokht 			if (cmlb_validate(dkp->dk_cmlbhandle, 0, 0) != 0)
952507c3241Smlf 				return (ENXIO);
953507c3241Smlf 
954507c3241Smlf 			if (cmlb_partinfo(dkp->dk_cmlbhandle, CMDKPART(dev),
955e8fb11a1Sshidokht 			    &p_lblkcnt, &p_lblksrt, NULL, NULL, 0))
956507c3241Smlf 				return (ENXIO);
957507c3241Smlf 
958507c3241Smlf 			if (p_lblkcnt <= 0)
959507c3241Smlf 				return (ENXIO);
960507c3241Smlf 		}
961507c3241Smlf 
962507c3241Smlf 		if (ddi_copyout(&state, (caddr_t)arg, sizeof (int), flag))
963507c3241Smlf 			return (EFAULT);
964507c3241Smlf 
965507c3241Smlf 		return (0);
966507c3241Smlf 	}
967507c3241Smlf 
968507c3241Smlf 	/*
969507c3241Smlf 	 * is media removable?
970507c3241Smlf 	 */
971507c3241Smlf 	case DKIOCREMOVABLE: {
972507c3241Smlf 		int i;
973507c3241Smlf 
974507c3241Smlf 		i = (DKTP_EXT->tg_rmb) ? 1 : 0;
975507c3241Smlf 
976507c3241Smlf 		if (ddi_copyout(&i, (caddr_t)arg, sizeof (int), flag))
977507c3241Smlf 			return (EFAULT);
978507c3241Smlf 
979507c3241Smlf 		return (0);
980507c3241Smlf 	}
981507c3241Smlf 
982507c3241Smlf 	case DKIOCADDBAD:
983507c3241Smlf 		/*
984507c3241Smlf 		 * This is not an update mechanism to add bad blocks
985507c3241Smlf 		 * to the bad block structures stored on disk.
986507c3241Smlf 		 *
987507c3241Smlf 		 * addbadsec(1M) will update the bad block data on disk
988507c3241Smlf 		 * and use this ioctl to force the driver to re-initialize
989507c3241Smlf 		 * the list of bad blocks in the driver.
990507c3241Smlf 		 */
991507c3241Smlf 
992507c3241Smlf 		/* start BBH */
993507c3241Smlf 		cmdk_bbh_reopen(dkp);
994507c3241Smlf 		return (0);
995507c3241Smlf 
996507c3241Smlf 	case DKIOCG_PHYGEOM:
997507c3241Smlf 	case DKIOCG_VIRTGEOM:
998507c3241Smlf 	case DKIOCGGEOM:
999507c3241Smlf 	case DKIOCSGEOM:
1000507c3241Smlf 	case DKIOCGAPART:
1001507c3241Smlf 	case DKIOCSAPART:
1002507c3241Smlf 	case DKIOCGVTOC:
1003507c3241Smlf 	case DKIOCSVTOC:
1004507c3241Smlf 	case DKIOCPARTINFO:
1005342440ecSPrasad Singamsetty 	case DKIOCGEXTVTOC:
1006342440ecSPrasad Singamsetty 	case DKIOCSEXTVTOC:
1007342440ecSPrasad Singamsetty 	case DKIOCEXTPARTINFO:
1008507c3241Smlf 	case DKIOCGMBOOT:
1009507c3241Smlf 	case DKIOCSMBOOT:
1010507c3241Smlf 	case DKIOCGETEFI:
1011507c3241Smlf 	case DKIOCSETEFI:
1012507c3241Smlf 	case DKIOCPARTITION:
1013aa1b14e7SSheshadri Vasudevan 	case DKIOCSETEXTPART:
1014507c3241Smlf 	{
1015507c3241Smlf 		int rc;
1016507c3241Smlf 
1017e8fb11a1Sshidokht 		rc = cmlb_ioctl(dkp->dk_cmlbhandle, dev, cmd, arg, flag,
1018e8fb11a1Sshidokht 		    credp, rvalp, 0);
10193b22643dSJan Setje-Eilers 		if (cmd == DKIOCSVTOC || cmd == DKIOCSEXTVTOC)
1020507c3241Smlf 			cmdk_devid_setup(dkp);
1021507c3241Smlf 		return (rc);
1022507c3241Smlf 	}
1023507c3241Smlf 
1024507c3241Smlf 	case DIOCTL_RWCMD: {
1025507c3241Smlf 		struct	dadkio_rwcmd *rwcmdp;
1026507c3241Smlf 		int	status;
1027507c3241Smlf 
1028507c3241Smlf 		rwcmdp = kmem_alloc(sizeof (struct dadkio_rwcmd), KM_SLEEP);
1029507c3241Smlf 
1030507c3241Smlf 		status = rwcmd_copyin(rwcmdp, (caddr_t)arg, flag);
1031507c3241Smlf 
1032507c3241Smlf 		if (status == 0) {
1033507c3241Smlf 			bzero(&(rwcmdp->status), sizeof (struct dadkio_status));
1034507c3241Smlf 			status = dadk_ioctl(DKTP_DATA,
1035507c3241Smlf 			    dev,
1036507c3241Smlf 			    cmd,
1037507c3241Smlf 			    (uintptr_t)rwcmdp,
1038507c3241Smlf 			    flag,
1039507c3241Smlf 			    credp,
1040507c3241Smlf 			    rvalp);
1041507c3241Smlf 		}
1042507c3241Smlf 		if (status == 0)
1043507c3241Smlf 			status = rwcmd_copyout(rwcmdp, (caddr_t)arg, flag);
1044507c3241Smlf 
1045507c3241Smlf 		kmem_free(rwcmdp, sizeof (struct dadkio_rwcmd));
1046507c3241Smlf 		return (status);
1047507c3241Smlf 	}
1048507c3241Smlf 
1049507c3241Smlf 	default:
1050507c3241Smlf 		return (dadk_ioctl(DKTP_DATA,
1051507c3241Smlf 		    dev,
1052507c3241Smlf 		    cmd,
1053507c3241Smlf 		    arg,
1054507c3241Smlf 		    flag,
1055507c3241Smlf 		    credp,
1056507c3241Smlf 		    rvalp));
1057507c3241Smlf 	}
1058507c3241Smlf }
1059507c3241Smlf 
1060507c3241Smlf /*ARGSUSED1*/
1061507c3241Smlf static int
1062507c3241Smlf cmdkclose(dev_t dev, int flag, int otyp, cred_t *credp)
1063507c3241Smlf {
1064507c3241Smlf 	int		part;
1065507c3241Smlf 	ulong_t		partbit;
1066507c3241Smlf 	int 		instance;
1067507c3241Smlf 	struct cmdk	*dkp;
1068507c3241Smlf 	int		lastclose = 1;
1069507c3241Smlf 	int		i;
1070507c3241Smlf 
1071507c3241Smlf 	instance = CMDKUNIT(dev);
1072507c3241Smlf 	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) ||
1073507c3241Smlf 	    (otyp >= OTYPCNT))
1074507c3241Smlf 		return (ENXIO);
1075507c3241Smlf 
1076507c3241Smlf 	mutex_enter(&dkp->dk_mutex);
1077507c3241Smlf 
1078507c3241Smlf 	/* check if device has been opened */
107906bbe1e0Sedp 	ASSERT(cmdk_isopen(dkp, dev));
1080507c3241Smlf 	if (!(dkp->dk_flag & CMDK_OPEN)) {
1081507c3241Smlf 		mutex_exit(&dkp->dk_mutex);
1082507c3241Smlf 		return (ENXIO);
1083507c3241Smlf 	}
1084507c3241Smlf 
10852df1fe9cSrandyf 	while (dkp->dk_flag & CMDK_SUSPEND) {
10862df1fe9cSrandyf 		cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
10872df1fe9cSrandyf 	}
10882df1fe9cSrandyf 
1089507c3241Smlf 	part = CMDKPART(dev);
1090507c3241Smlf 	partbit = 1 << part;
1091507c3241Smlf 
1092507c3241Smlf 	/* account for close */
1093507c3241Smlf 	if (otyp == OTYP_LYR) {
109406bbe1e0Sedp 		ASSERT(dkp->dk_open_lyr[part] > 0);
1095507c3241Smlf 		if (dkp->dk_open_lyr[part])
1096507c3241Smlf 			dkp->dk_open_lyr[part]--;
109706bbe1e0Sedp 	} else {
109806bbe1e0Sedp 		ASSERT((dkp->dk_open_reg[otyp] & partbit) != 0);
1099507c3241Smlf 		dkp->dk_open_reg[otyp] &= ~partbit;
110006bbe1e0Sedp 	}
1101507c3241Smlf 	dkp->dk_open_exl &= ~partbit;
1102507c3241Smlf 
1103507c3241Smlf 	for (i = 0; i < CMDK_MAXPART; i++)
1104507c3241Smlf 		if (dkp->dk_open_lyr[i] != 0) {
1105507c3241Smlf 			lastclose = 0;
1106507c3241Smlf 			break;
1107507c3241Smlf 		}
1108507c3241Smlf 
1109507c3241Smlf 	if (lastclose)
1110507c3241Smlf 		for (i = 0; i < OTYPCNT; i++)
1111507c3241Smlf 			if (dkp->dk_open_reg[i] != 0) {
1112507c3241Smlf 				lastclose = 0;
1113507c3241Smlf 				break;
1114507c3241Smlf 			}
1115507c3241Smlf 
1116507c3241Smlf 	mutex_exit(&dkp->dk_mutex);
1117507c3241Smlf 
1118507c3241Smlf 	if (lastclose)
1119e8fb11a1Sshidokht 		cmlb_invalidate(dkp->dk_cmlbhandle, 0);
1120507c3241Smlf 
1121507c3241Smlf 	return (DDI_SUCCESS);
1122507c3241Smlf }
1123507c3241Smlf 
1124507c3241Smlf /*ARGSUSED3*/
1125507c3241Smlf static int
1126507c3241Smlf cmdkopen(dev_t *dev_p, int flag, int otyp, cred_t *credp)
1127507c3241Smlf {
1128507c3241Smlf 	dev_t		dev = *dev_p;
1129507c3241Smlf 	int 		part;
1130507c3241Smlf 	ulong_t		partbit;
1131507c3241Smlf 	int 		instance;
1132507c3241Smlf 	struct	cmdk	*dkp;
1133507c3241Smlf 	diskaddr_t	p_lblksrt;
1134507c3241Smlf 	diskaddr_t	p_lblkcnt;
1135507c3241Smlf 	int		i;
1136507c3241Smlf 	int		nodelay;
1137507c3241Smlf 
1138507c3241Smlf 	instance = CMDKUNIT(dev);
1139507c3241Smlf 	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
1140507c3241Smlf 		return (ENXIO);
1141507c3241Smlf 
1142507c3241Smlf 	if (otyp >= OTYPCNT)
1143507c3241Smlf 		return (EINVAL);
1144507c3241Smlf 
11452df1fe9cSrandyf 	mutex_enter(&dkp->dk_mutex);
11462df1fe9cSrandyf 	while (dkp->dk_flag & CMDK_SUSPEND) {
11472df1fe9cSrandyf 		cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
11482df1fe9cSrandyf 	}
11492df1fe9cSrandyf 	mutex_exit(&dkp->dk_mutex);
11502df1fe9cSrandyf 
1151507c3241Smlf 	part = CMDKPART(dev);
1152507c3241Smlf 	partbit = 1 << part;
1153507c3241Smlf 	nodelay = (flag & (FNDELAY | FNONBLOCK));
1154507c3241Smlf 
1155507c3241Smlf 	mutex_enter(&dkp->dk_mutex);
1156507c3241Smlf 
1157e8fb11a1Sshidokht 	if (cmlb_validate(dkp->dk_cmlbhandle, 0, 0) != 0) {
1158507c3241Smlf 
1159507c3241Smlf 		/* fail if not doing non block open */
1160507c3241Smlf 		if (!nodelay) {
1161507c3241Smlf 			mutex_exit(&dkp->dk_mutex);
1162507c3241Smlf 			return (ENXIO);
1163507c3241Smlf 		}
1164507c3241Smlf 	} else if (cmlb_partinfo(dkp->dk_cmlbhandle, part, &p_lblkcnt,
1165e8fb11a1Sshidokht 	    &p_lblksrt, NULL, NULL, 0) == 0) {
1166507c3241Smlf 
1167507c3241Smlf 		if (p_lblkcnt <= 0 && (!nodelay || otyp != OTYP_CHR)) {
1168507c3241Smlf 			mutex_exit(&dkp->dk_mutex);
1169507c3241Smlf 			return (ENXIO);
1170507c3241Smlf 		}
1171507c3241Smlf 	} else {
1172507c3241Smlf 		/* fail if not doing non block open */
1173507c3241Smlf 		if (!nodelay) {
1174507c3241Smlf 			mutex_exit(&dkp->dk_mutex);
1175507c3241Smlf 			return (ENXIO);
1176507c3241Smlf 		}
1177507c3241Smlf 	}
1178507c3241Smlf 
1179507c3241Smlf 	if ((DKTP_EXT->tg_rdonly) && (flag & FWRITE)) {
1180507c3241Smlf 		mutex_exit(&dkp->dk_mutex);
1181507c3241Smlf 		return (EROFS);
1182507c3241Smlf 	}
1183507c3241Smlf 
1184507c3241Smlf 	/* check for part already opend exclusively */
1185507c3241Smlf 	if (dkp->dk_open_exl & partbit)
1186507c3241Smlf 		goto excl_open_fail;
1187507c3241Smlf 
1188507c3241Smlf 	/* check if we can establish exclusive open */
1189507c3241Smlf 	if (flag & FEXCL) {
1190507c3241Smlf 		if (dkp->dk_open_lyr[part])
1191507c3241Smlf 			goto excl_open_fail;
1192507c3241Smlf 		for (i = 0; i < OTYPCNT; i++) {
1193507c3241Smlf 			if (dkp->dk_open_reg[i] & partbit)
1194507c3241Smlf 				goto excl_open_fail;
1195507c3241Smlf 		}
1196507c3241Smlf 	}
1197507c3241Smlf 
1198507c3241Smlf 	/* open will succeed, account for open */
1199507c3241Smlf 	dkp->dk_flag |= CMDK_OPEN;
1200507c3241Smlf 	if (otyp == OTYP_LYR)
1201507c3241Smlf 		dkp->dk_open_lyr[part]++;
1202507c3241Smlf 	else
1203507c3241Smlf 		dkp->dk_open_reg[otyp] |= partbit;
1204507c3241Smlf 	if (flag & FEXCL)
1205507c3241Smlf 		dkp->dk_open_exl |= partbit;
1206507c3241Smlf 
1207507c3241Smlf 	mutex_exit(&dkp->dk_mutex);
1208507c3241Smlf 	return (DDI_SUCCESS);
1209507c3241Smlf 
1210507c3241Smlf excl_open_fail:
1211507c3241Smlf 	mutex_exit(&dkp->dk_mutex);
1212507c3241Smlf 	return (EBUSY);
1213507c3241Smlf }
1214507c3241Smlf 
1215507c3241Smlf /*
1216507c3241Smlf  * read routine
1217507c3241Smlf  */
1218507c3241Smlf /*ARGSUSED2*/
1219507c3241Smlf static int
1220507c3241Smlf cmdkread(dev_t dev, struct uio *uio, cred_t *credp)
1221507c3241Smlf {
1222507c3241Smlf 	return (cmdkrw(dev, uio, B_READ));
1223507c3241Smlf }
1224507c3241Smlf 
1225507c3241Smlf /*
1226507c3241Smlf  * async read routine
1227507c3241Smlf  */
1228507c3241Smlf /*ARGSUSED2*/
1229507c3241Smlf static int
1230507c3241Smlf cmdkaread(dev_t dev, struct aio_req *aio, cred_t *credp)
1231507c3241Smlf {
1232507c3241Smlf 	return (cmdkarw(dev, aio, B_READ));
1233507c3241Smlf }
1234507c3241Smlf 
1235507c3241Smlf /*
1236507c3241Smlf  * write routine
1237507c3241Smlf  */
1238507c3241Smlf /*ARGSUSED2*/
1239507c3241Smlf static int
1240507c3241Smlf cmdkwrite(dev_t dev, struct uio *uio, cred_t *credp)
1241507c3241Smlf {
1242507c3241Smlf 	return (cmdkrw(dev, uio, B_WRITE));
1243507c3241Smlf }
1244507c3241Smlf 
1245507c3241Smlf /*
1246507c3241Smlf  * async write routine
1247507c3241Smlf  */
1248507c3241Smlf /*ARGSUSED2*/
1249507c3241Smlf static int
1250507c3241Smlf cmdkawrite(dev_t dev, struct aio_req *aio, cred_t *credp)
1251507c3241Smlf {
1252507c3241Smlf 	return (cmdkarw(dev, aio, B_WRITE));
1253507c3241Smlf }
1254507c3241Smlf 
1255507c3241Smlf static void
1256507c3241Smlf cmdkmin(struct buf *bp)
1257507c3241Smlf {
1258507c3241Smlf 	if (bp->b_bcount > DK_MAXRECSIZE)
1259507c3241Smlf 		bp->b_bcount = DK_MAXRECSIZE;
1260507c3241Smlf }
1261507c3241Smlf 
1262507c3241Smlf static int
1263507c3241Smlf cmdkrw(dev_t dev, struct uio *uio, int flag)
1264507c3241Smlf {
12652df1fe9cSrandyf 	int 		instance;
12662df1fe9cSrandyf 	struct	cmdk	*dkp;
12672df1fe9cSrandyf 
12682df1fe9cSrandyf 	instance = CMDKUNIT(dev);
12692df1fe9cSrandyf 	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
12702df1fe9cSrandyf 		return (ENXIO);
12712df1fe9cSrandyf 
12722df1fe9cSrandyf 	mutex_enter(&dkp->dk_mutex);
12732df1fe9cSrandyf 	while (dkp->dk_flag & CMDK_SUSPEND) {
12742df1fe9cSrandyf 		cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
12752df1fe9cSrandyf 	}
12762df1fe9cSrandyf 	mutex_exit(&dkp->dk_mutex);
12772df1fe9cSrandyf 
1278507c3241Smlf 	return (physio(cmdkstrategy, (struct buf *)0, dev, flag, cmdkmin, uio));
1279507c3241Smlf }
1280507c3241Smlf 
1281507c3241Smlf static int
1282507c3241Smlf cmdkarw(dev_t dev, struct aio_req *aio, int flag)
1283507c3241Smlf {
12842df1fe9cSrandyf 	int 		instance;
12852df1fe9cSrandyf 	struct	cmdk	*dkp;
12862df1fe9cSrandyf 
12872df1fe9cSrandyf 	instance = CMDKUNIT(dev);
12882df1fe9cSrandyf 	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
12892df1fe9cSrandyf 		return (ENXIO);
12902df1fe9cSrandyf 
12912df1fe9cSrandyf 	mutex_enter(&dkp->dk_mutex);
12922df1fe9cSrandyf 	while (dkp->dk_flag & CMDK_SUSPEND) {
12932df1fe9cSrandyf 		cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
12942df1fe9cSrandyf 	}
12952df1fe9cSrandyf 	mutex_exit(&dkp->dk_mutex);
12962df1fe9cSrandyf 
1297507c3241Smlf 	return (aphysio(cmdkstrategy, anocancel, dev, flag, cmdkmin, aio));
1298507c3241Smlf }
1299507c3241Smlf 
1300507c3241Smlf /*
1301507c3241Smlf  * strategy routine
1302507c3241Smlf  */
1303507c3241Smlf static int
1304507c3241Smlf cmdkstrategy(struct buf *bp)
1305507c3241Smlf {
1306507c3241Smlf 	int 		instance;
1307507c3241Smlf 	struct	cmdk 	*dkp;
1308507c3241Smlf 	long		d_cnt;
1309507c3241Smlf 	diskaddr_t	p_lblksrt;
1310507c3241Smlf 	diskaddr_t	p_lblkcnt;
1311507c3241Smlf 
1312507c3241Smlf 	instance = CMDKUNIT(bp->b_edev);
1313507c3241Smlf 	if (cmdk_indump || !(dkp = ddi_get_soft_state(cmdk_state, instance)) ||
1314507c3241Smlf 	    (dkblock(bp) < 0)) {
1315507c3241Smlf 		bp->b_resid = bp->b_bcount;
1316507c3241Smlf 		SETBPERR(bp, ENXIO);
1317507c3241Smlf 		biodone(bp);
1318507c3241Smlf 		return (0);
1319507c3241Smlf 	}
1320507c3241Smlf 
13212df1fe9cSrandyf 	mutex_enter(&dkp->dk_mutex);
132206bbe1e0Sedp 	ASSERT(cmdk_isopen(dkp, bp->b_edev));
13232df1fe9cSrandyf 	while (dkp->dk_flag & CMDK_SUSPEND) {
13242df1fe9cSrandyf 		cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
13252df1fe9cSrandyf 	}
13262df1fe9cSrandyf 	mutex_exit(&dkp->dk_mutex);
13272df1fe9cSrandyf 
1328507c3241Smlf 	bp->b_flags &= ~(B_DONE|B_ERROR);
1329507c3241Smlf 	bp->b_resid = 0;
1330507c3241Smlf 	bp->av_back = NULL;
1331507c3241Smlf 
1332507c3241Smlf 	/*
1333507c3241Smlf 	 * only re-read the vtoc if necessary (force == FALSE)
1334507c3241Smlf 	 */
1335e8fb11a1Sshidokht 	if (cmlb_partinfo(dkp->dk_cmlbhandle, CMDKPART(bp->b_edev),
1336e8fb11a1Sshidokht 	    &p_lblkcnt, &p_lblksrt, NULL, NULL, 0)) {
1337507c3241Smlf 		SETBPERR(bp, ENXIO);
1338507c3241Smlf 	}
1339507c3241Smlf 
1340507c3241Smlf 	if ((bp->b_bcount & (NBPSCTR-1)) || (dkblock(bp) > p_lblkcnt))
1341507c3241Smlf 		SETBPERR(bp, ENXIO);
1342507c3241Smlf 
1343507c3241Smlf 	if ((bp->b_flags & B_ERROR) || (dkblock(bp) == p_lblkcnt)) {
1344507c3241Smlf 		bp->b_resid = bp->b_bcount;
1345507c3241Smlf 		biodone(bp);
1346507c3241Smlf 		return (0);
1347507c3241Smlf 	}
1348507c3241Smlf 
1349507c3241Smlf 	d_cnt = bp->b_bcount >> SCTRSHFT;
1350507c3241Smlf 	if ((dkblock(bp) + d_cnt) > p_lblkcnt) {
1351507c3241Smlf 		bp->b_resid = ((dkblock(bp) + d_cnt) - p_lblkcnt) << SCTRSHFT;
1352507c3241Smlf 		bp->b_bcount -= bp->b_resid;
1353507c3241Smlf 	}
1354507c3241Smlf 
1355507c3241Smlf 	SET_BP_SEC(bp, ((ulong_t)(p_lblksrt + dkblock(bp))));
1356507c3241Smlf 	if (dadk_strategy(DKTP_DATA, bp) != DDI_SUCCESS) {
1357507c3241Smlf 		bp->b_resid += bp->b_bcount;
1358507c3241Smlf 		biodone(bp);
1359507c3241Smlf 	}
1360507c3241Smlf 	return (0);
1361507c3241Smlf }
1362507c3241Smlf 
1363507c3241Smlf static int
1364507c3241Smlf cmdk_create_obj(dev_info_t *dip, struct cmdk *dkp)
1365507c3241Smlf {
1366507c3241Smlf 	struct scsi_device *devp;
1367507c3241Smlf 	opaque_t	queobjp = NULL;
1368507c3241Smlf 	opaque_t	flcobjp = NULL;
1369507c3241Smlf 	char		que_keyvalp[64];
1370507c3241Smlf 	int		que_keylen;
1371507c3241Smlf 	char		flc_keyvalp[64];
1372507c3241Smlf 	int		flc_keylen;
1373507c3241Smlf 
1374507c3241Smlf 	ASSERT(mutex_owned(&dkp->dk_mutex));
1375507c3241Smlf 
1376507c3241Smlf 	/* Create linkage to queueing routines based on property */
1377507c3241Smlf 	que_keylen = sizeof (que_keyvalp);
1378507c3241Smlf 	if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF,
1379507c3241Smlf 	    DDI_PROP_CANSLEEP, "queue", que_keyvalp, &que_keylen) !=
1380507c3241Smlf 	    DDI_PROP_SUCCESS) {
1381507c3241Smlf 		cmn_err(CE_WARN, "cmdk_create_obj: queue property undefined");
1382507c3241Smlf 		return (DDI_FAILURE);
1383507c3241Smlf 	}
1384507c3241Smlf 	que_keyvalp[que_keylen] = (char)0;
1385507c3241Smlf 
1386507c3241Smlf 	if (strcmp(que_keyvalp, "qfifo") == 0) {
1387507c3241Smlf 		queobjp = (opaque_t)qfifo_create();
1388507c3241Smlf 	} else if (strcmp(que_keyvalp, "qsort") == 0) {
1389507c3241Smlf 		queobjp = (opaque_t)qsort_create();
1390507c3241Smlf 	} else {
1391507c3241Smlf 		return (DDI_FAILURE);
1392507c3241Smlf 	}
1393507c3241Smlf 
1394507c3241Smlf 	/* Create linkage to dequeueing routines based on property */
1395507c3241Smlf 	flc_keylen = sizeof (flc_keyvalp);
1396507c3241Smlf 	if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF,
1397507c3241Smlf 	    DDI_PROP_CANSLEEP, "flow_control", flc_keyvalp, &flc_keylen) !=
1398507c3241Smlf 	    DDI_PROP_SUCCESS) {
1399507c3241Smlf 		cmn_err(CE_WARN,
1400507c3241Smlf 		    "cmdk_create_obj: flow-control property undefined");
1401507c3241Smlf 		return (DDI_FAILURE);
1402507c3241Smlf 	}
1403507c3241Smlf 
1404507c3241Smlf 	flc_keyvalp[flc_keylen] = (char)0;
1405507c3241Smlf 
1406507c3241Smlf 	if (strcmp(flc_keyvalp, "dsngl") == 0) {
1407507c3241Smlf 		flcobjp = (opaque_t)dsngl_create();
1408507c3241Smlf 	} else if (strcmp(flc_keyvalp, "dmult") == 0) {
1409507c3241Smlf 		flcobjp = (opaque_t)dmult_create();
1410507c3241Smlf 	} else {
1411507c3241Smlf 		return (DDI_FAILURE);
1412507c3241Smlf 	}
1413507c3241Smlf 
1414507c3241Smlf 	/* populate bbh_obj object stored in dkp */
1415507c3241Smlf 	dkp->dk_bbh_obj.bbh_data = dkp;
1416507c3241Smlf 	dkp->dk_bbh_obj.bbh_ops = &cmdk_bbh_ops;
1417507c3241Smlf 
1418507c3241Smlf 	/* create linkage to dadk */
1419507c3241Smlf 	dkp->dk_tgobjp = (opaque_t)dadk_create();
1420507c3241Smlf 
1421507c3241Smlf 	devp = ddi_get_driver_private(dip);
1422507c3241Smlf 	(void) dadk_init(DKTP_DATA, devp, flcobjp, queobjp, &dkp->dk_bbh_obj,
1423507c3241Smlf 	    NULL);
1424507c3241Smlf 
1425507c3241Smlf 	return (DDI_SUCCESS);
1426507c3241Smlf }
1427507c3241Smlf 
1428507c3241Smlf static void
1429507c3241Smlf cmdk_destroy_obj(dev_info_t *dip, struct cmdk *dkp)
1430507c3241Smlf {
1431507c3241Smlf 	char		que_keyvalp[64];
1432507c3241Smlf 	int		que_keylen;
1433507c3241Smlf 	char		flc_keyvalp[64];
1434507c3241Smlf 	int		flc_keylen;
1435507c3241Smlf 
1436507c3241Smlf 	ASSERT(mutex_owned(&dkp->dk_mutex));
1437507c3241Smlf 
1438507c3241Smlf 	(void) dadk_free((dkp->dk_tgobjp));
1439507c3241Smlf 	dkp->dk_tgobjp = NULL;
1440507c3241Smlf 
1441507c3241Smlf 	que_keylen = sizeof (que_keyvalp);
1442507c3241Smlf 	if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF,
1443507c3241Smlf 	    DDI_PROP_CANSLEEP, "queue", que_keyvalp, &que_keylen) !=
1444507c3241Smlf 	    DDI_PROP_SUCCESS) {
1445507c3241Smlf 		cmn_err(CE_WARN, "cmdk_destroy_obj: queue property undefined");
1446507c3241Smlf 		return;
1447507c3241Smlf 	}
1448507c3241Smlf 	que_keyvalp[que_keylen] = (char)0;
1449507c3241Smlf 
1450507c3241Smlf 	flc_keylen = sizeof (flc_keyvalp);
1451507c3241Smlf 	if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF,
1452507c3241Smlf 	    DDI_PROP_CANSLEEP, "flow_control", flc_keyvalp, &flc_keylen) !=
1453507c3241Smlf 	    DDI_PROP_SUCCESS) {
1454507c3241Smlf 		cmn_err(CE_WARN,
1455507c3241Smlf 		    "cmdk_destroy_obj: flow-control property undefined");
1456507c3241Smlf 		return;
1457507c3241Smlf 	}
1458507c3241Smlf 	flc_keyvalp[flc_keylen] = (char)0;
1459507c3241Smlf }
1460e8fb11a1Sshidokht /*ARGSUSED5*/
1461507c3241Smlf static int
1462e8fb11a1Sshidokht cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr,
1463e8fb11a1Sshidokht     diskaddr_t start, size_t count, void *tg_cookie)
1464507c3241Smlf {
1465507c3241Smlf 	struct cmdk	*dkp;
1466507c3241Smlf 	opaque_t	handle;
1467507c3241Smlf 	int		rc = 0;
1468507c3241Smlf 	char		*bufa;
1469de6d0fcdSShidokht Yadegari 	size_t		buflen;
1470507c3241Smlf 
1471507c3241Smlf 	dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip));
1472507c3241Smlf 	if (dkp == NULL)
1473507c3241Smlf 		return (ENXIO);
1474507c3241Smlf 
1475507c3241Smlf 	if (cmd != TG_READ && cmd != TG_WRITE)
1476507c3241Smlf 		return (EINVAL);
1477507c3241Smlf 
1478de6d0fcdSShidokht Yadegari 	/* buflen must be multiple of 512 */
1479de6d0fcdSShidokht Yadegari 	buflen = (count + NBPSCTR - 1) & -NBPSCTR;
1480de6d0fcdSShidokht Yadegari 	handle = dadk_iob_alloc(DKTP_DATA, start, buflen, KM_SLEEP);
1481507c3241Smlf 	if (!handle)
1482507c3241Smlf 		return (ENOMEM);
1483507c3241Smlf 
1484507c3241Smlf 	if (cmd == TG_READ) {
1485507c3241Smlf 		bufa = dadk_iob_xfer(DKTP_DATA, handle, B_READ);
1486507c3241Smlf 		if (!bufa)
1487507c3241Smlf 			rc = EIO;
1488507c3241Smlf 		else
1489507c3241Smlf 			bcopy(bufa, bufaddr, count);
1490507c3241Smlf 	} else {
1491507c3241Smlf 		bufa = dadk_iob_htoc(DKTP_DATA, handle);
1492507c3241Smlf 		bcopy(bufaddr, bufa, count);
1493507c3241Smlf 		bufa = dadk_iob_xfer(DKTP_DATA, handle, B_WRITE);
1494507c3241Smlf 		if (!bufa)
1495507c3241Smlf 			rc = EIO;
1496507c3241Smlf 	}
1497507c3241Smlf 	(void) dadk_iob_free(DKTP_DATA, handle);
1498507c3241Smlf 
1499507c3241Smlf 	return (rc);
1500507c3241Smlf }
1501507c3241Smlf 
1502e8fb11a1Sshidokht /*ARGSUSED3*/
1503507c3241Smlf static int
1504e8fb11a1Sshidokht cmdk_lb_getinfo(dev_info_t *dip, int cmd, void *arg, void *tg_cookie)
1505507c3241Smlf {
1506e8fb11a1Sshidokht 
1507507c3241Smlf 	struct cmdk		*dkp;
1508507c3241Smlf 	struct tgdk_geom	phyg;
1509507c3241Smlf 
1510e8fb11a1Sshidokht 
1511507c3241Smlf 	dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip));
1512507c3241Smlf 	if (dkp == NULL)
1513507c3241Smlf 		return (ENXIO);
1514507c3241Smlf 
1515e8fb11a1Sshidokht 	switch (cmd) {
1516e8fb11a1Sshidokht 	case TG_GETPHYGEOM: {
1517e8fb11a1Sshidokht 		cmlb_geom_t *phygeomp = (cmlb_geom_t *)arg;
1518e8fb11a1Sshidokht 
1519507c3241Smlf 		/* dadk_getphygeom always returns success */
1520507c3241Smlf 		(void) dadk_getphygeom(DKTP_DATA, &phyg);
1521507c3241Smlf 
1522e8fb11a1Sshidokht 		phygeomp->g_capacity	= phyg.g_cap;
1523e8fb11a1Sshidokht 		phygeomp->g_nsect	= phyg.g_sec;
1524e8fb11a1Sshidokht 		phygeomp->g_nhead	= phyg.g_head;
1525e8fb11a1Sshidokht 		phygeomp->g_acyl	= phyg.g_acyl;
1526e8fb11a1Sshidokht 		phygeomp->g_ncyl	= phyg.g_cyl;
1527e8fb11a1Sshidokht 		phygeomp->g_secsize	= phyg.g_secsiz;
1528e8fb11a1Sshidokht 		phygeomp->g_intrlv	= 1;
1529e8fb11a1Sshidokht 		phygeomp->g_rpm		= 3600;
1530507c3241Smlf 
1531507c3241Smlf 		return (0);
1532507c3241Smlf 	}
1533507c3241Smlf 
1534e8fb11a1Sshidokht 	case TG_GETVIRTGEOM: {
1535e8fb11a1Sshidokht 		cmlb_geom_t *virtgeomp = (cmlb_geom_t *)arg;
1536507c3241Smlf 		diskaddr_t		capacity;
1537507c3241Smlf 
1538507c3241Smlf 		(void) dadk_getgeom(DKTP_DATA, &phyg);
1539507c3241Smlf 		capacity = phyg.g_cap;
1540507c3241Smlf 
1541507c3241Smlf 		/*
1542507c3241Smlf 		 * If the controller returned us something that doesn't
1543507c3241Smlf 		 * really fit into an Int 13/function 8 geometry
1544507c3241Smlf 		 * result, just fail the ioctl.  See PSARC 1998/313.
1545507c3241Smlf 		 */
1546507c3241Smlf 		if (capacity < 0 || capacity >= 63 * 254 * 1024)
1547507c3241Smlf 			return (EINVAL);
1548507c3241Smlf 
1549507c3241Smlf 		virtgeomp->g_capacity	= capacity;
1550507c3241Smlf 		virtgeomp->g_nsect	= 63;
1551507c3241Smlf 		virtgeomp->g_nhead	= 254;
1552507c3241Smlf 		virtgeomp->g_ncyl	= capacity / (63 * 254);
1553507c3241Smlf 		virtgeomp->g_acyl	= 0;
1554507c3241Smlf 		virtgeomp->g_secsize	= 512;
1555507c3241Smlf 		virtgeomp->g_intrlv	= 1;
1556507c3241Smlf 		virtgeomp->g_rpm	= 3600;
1557507c3241Smlf 
1558507c3241Smlf 		return (0);
1559507c3241Smlf 	}
1560507c3241Smlf 
1561e8fb11a1Sshidokht 	case TG_GETCAPACITY:
1562e8fb11a1Sshidokht 	case TG_GETBLOCKSIZE:
1563507c3241Smlf 	{
1564507c3241Smlf 
1565507c3241Smlf 		/* dadk_getphygeom always returns success */
1566507c3241Smlf 		(void) dadk_getphygeom(DKTP_DATA, &phyg);
1567e8fb11a1Sshidokht 		if (cmd == TG_GETCAPACITY)
1568e8fb11a1Sshidokht 			*(diskaddr_t *)arg = phyg.g_cap;
1569e8fb11a1Sshidokht 		else
1570e8fb11a1Sshidokht 			*(uint32_t *)arg = (uint32_t)phyg.g_secsiz;
1571507c3241Smlf 
1572507c3241Smlf 		return (0);
1573507c3241Smlf 	}
1574507c3241Smlf 
1575e8fb11a1Sshidokht 	case TG_GETATTR: {
1576e8fb11a1Sshidokht 		tg_attribute_t *tgattribute = (tg_attribute_t *)arg;
1577507c3241Smlf 		if ((DKTP_EXT->tg_rdonly))
1578507c3241Smlf 			tgattribute->media_is_writable = FALSE;
1579507c3241Smlf 		else
1580507c3241Smlf 			tgattribute->media_is_writable = TRUE;
1581*b2b61b8fSYuri Pankov 		tgattribute->media_is_rotational = TRUE;
1582507c3241Smlf 
1583507c3241Smlf 		return (0);
1584507c3241Smlf 	}
1585507c3241Smlf 
1586e8fb11a1Sshidokht 	default:
1587e8fb11a1Sshidokht 		return (ENOTTY);
1588e8fb11a1Sshidokht 	}
1589e8fb11a1Sshidokht }
1590e8fb11a1Sshidokht 
1591e8fb11a1Sshidokht 
1592e8fb11a1Sshidokht 
1593e8fb11a1Sshidokht 
1594e8fb11a1Sshidokht 
1595507c3241Smlf /*
1596507c3241Smlf  * Create and register the devid.
1597507c3241Smlf  * There are 4 different ways we can get a device id:
1598507c3241Smlf  *    1. Already have one - nothing to do
1599507c3241Smlf  *    2. Build one from the drive's model and serial numbers
1600507c3241Smlf  *    3. Read one from the disk (first sector of last track)
1601507c3241Smlf  *    4. Fabricate one and write it on the disk.
1602507c3241Smlf  * If any of these succeeds, register the deviceid
1603507c3241Smlf  */
1604507c3241Smlf static void
1605507c3241Smlf cmdk_devid_setup(struct cmdk *dkp)
1606507c3241Smlf {
1607507c3241Smlf 	int	rc;
1608507c3241Smlf 
1609507c3241Smlf 	/* Try options until one succeeds, or all have failed */
1610507c3241Smlf 
1611507c3241Smlf 	/* 1. All done if already registered */
1612507c3241Smlf 	if (dkp->dk_devid != NULL)
1613507c3241Smlf 		return;
1614507c3241Smlf 
1615507c3241Smlf 	/* 2. Build a devid from the model and serial number */
1616507c3241Smlf 	rc = cmdk_devid_modser(dkp);
1617507c3241Smlf 	if (rc != DDI_SUCCESS) {
1618507c3241Smlf 		/* 3. Read devid from the disk, if present */
1619507c3241Smlf 		rc = cmdk_devid_read(dkp);
1620507c3241Smlf 
1621507c3241Smlf 		/* 4. otherwise make one up and write it on the disk */
1622507c3241Smlf 		if (rc != DDI_SUCCESS)
1623507c3241Smlf 			rc = cmdk_devid_fabricate(dkp);
1624507c3241Smlf 	}
1625507c3241Smlf 
1626507c3241Smlf 	/* If we managed to get a devid any of the above ways, register it */
1627507c3241Smlf 	if (rc == DDI_SUCCESS)
1628507c3241Smlf 		(void) ddi_devid_register(dkp->dk_dip, dkp->dk_devid);
1629507c3241Smlf 
1630507c3241Smlf }
1631507c3241Smlf 
1632507c3241Smlf /*
1633507c3241Smlf  * Build a devid from the model and serial number
1634507c3241Smlf  * Return DDI_SUCCESS or DDI_FAILURE.
1635507c3241Smlf  */
1636507c3241Smlf static int
1637507c3241Smlf cmdk_devid_modser(struct cmdk *dkp)
1638507c3241Smlf {
1639507c3241Smlf 	int	rc = DDI_FAILURE;
1640507c3241Smlf 	char	*hwid;
1641507c3241Smlf 	int	modlen;
1642507c3241Smlf 	int	serlen;
1643507c3241Smlf 
1644507c3241Smlf 	/*
1645507c3241Smlf 	 * device ID is a concatenation of model number, '=', serial number.
1646507c3241Smlf 	 */
1647507c3241Smlf 	hwid = kmem_alloc(CMDK_HWIDLEN, KM_SLEEP);
1648507c3241Smlf 	modlen = cmdk_get_modser(dkp, DIOCTL_GETMODEL, hwid, CMDK_HWIDLEN);
1649507c3241Smlf 	if (modlen == 0) {
1650507c3241Smlf 		rc = DDI_FAILURE;
1651507c3241Smlf 		goto err;
1652507c3241Smlf 	}
1653507c3241Smlf 	hwid[modlen++] = '=';
1654507c3241Smlf 	serlen = cmdk_get_modser(dkp, DIOCTL_GETSERIAL,
1655507c3241Smlf 	    hwid + modlen, CMDK_HWIDLEN - modlen);
1656507c3241Smlf 	if (serlen == 0) {
1657507c3241Smlf 		rc = DDI_FAILURE;
1658507c3241Smlf 		goto err;
1659507c3241Smlf 	}
1660507c3241Smlf 	hwid[modlen + serlen] = 0;
1661507c3241Smlf 
1662507c3241Smlf 	/* Initialize the device ID, trailing NULL not included */
1663507c3241Smlf 	rc = ddi_devid_init(dkp->dk_dip, DEVID_ATA_SERIAL, modlen + serlen,
16643d510deaSMark Logan 	    hwid, &dkp->dk_devid);
1665507c3241Smlf 	if (rc != DDI_SUCCESS) {
1666507c3241Smlf 		rc = DDI_FAILURE;
1667507c3241Smlf 		goto err;
1668507c3241Smlf 	}
1669507c3241Smlf 
1670507c3241Smlf 	rc = DDI_SUCCESS;
1671507c3241Smlf 
1672507c3241Smlf err:
1673507c3241Smlf 	kmem_free(hwid, CMDK_HWIDLEN);
1674507c3241Smlf 	return (rc);
1675507c3241Smlf }
1676507c3241Smlf 
1677507c3241Smlf static int
1678507c3241Smlf cmdk_get_modser(struct cmdk *dkp, int ioccmd, char *buf, int len)
1679507c3241Smlf {
1680507c3241Smlf 	dadk_ioc_string_t strarg;
1681507c3241Smlf 	int		rval;
1682507c3241Smlf 	char		*s;
1683507c3241Smlf 	char		ch;
1684507c3241Smlf 	boolean_t	ret;
1685507c3241Smlf 	int		i;
1686507c3241Smlf 	int		tb;
1687507c3241Smlf 
1688507c3241Smlf 	strarg.is_buf = buf;
1689507c3241Smlf 	strarg.is_size = len;
1690507c3241Smlf 	if (dadk_ioctl(DKTP_DATA,
1691507c3241Smlf 	    dkp->dk_dev,
1692507c3241Smlf 	    ioccmd,
1693507c3241Smlf 	    (uintptr_t)&strarg,
1694507c3241Smlf 	    FNATIVE | FKIOCTL,
1695507c3241Smlf 	    NULL,
1696507c3241Smlf 	    &rval) != 0)
1697507c3241Smlf 		return (0);
1698507c3241Smlf 
1699507c3241Smlf 	/*
1700507c3241Smlf 	 * valid model/serial string must contain a non-zero non-space
1701507c3241Smlf 	 * trim trailing spaces/NULL
1702507c3241Smlf 	 */
1703507c3241Smlf 	ret = B_FALSE;
1704507c3241Smlf 	s = buf;
1705507c3241Smlf 	for (i = 0; i < strarg.is_size; i++) {
1706507c3241Smlf 		ch = *s++;
1707507c3241Smlf 		if (ch != ' ' && ch != '\0')
1708507c3241Smlf 			tb = i + 1;
1709507c3241Smlf 		if (ch != ' ' && ch != '\0' && ch != '0')
1710507c3241Smlf 			ret = B_TRUE;
1711507c3241Smlf 	}
1712507c3241Smlf 
1713507c3241Smlf 	if (ret == B_FALSE)
1714507c3241Smlf 		return (0);
1715507c3241Smlf 
1716507c3241Smlf 	return (tb);
1717507c3241Smlf }
1718507c3241Smlf 
1719507c3241Smlf /*
1720507c3241Smlf  * Read a devid from on the first block of the last track of
1721507c3241Smlf  * the last cylinder.  Make sure what we read is a valid devid.
1722507c3241Smlf  * Return DDI_SUCCESS or DDI_FAILURE.
1723507c3241Smlf  */
1724507c3241Smlf static int
1725507c3241Smlf cmdk_devid_read(struct cmdk *dkp)
1726507c3241Smlf {
1727507c3241Smlf 	diskaddr_t	blk;
1728507c3241Smlf 	struct dk_devid *dkdevidp;
1729507c3241Smlf 	uint_t		*ip;
1730507c3241Smlf 	int		chksum;
1731507c3241Smlf 	int		i, sz;
1732e4da943dSMark Logan 	tgdk_iob_handle	handle = NULL;
1733507c3241Smlf 	int		rc = DDI_FAILURE;
1734507c3241Smlf 
1735e8fb11a1Sshidokht 	if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0))
1736507c3241Smlf 		goto err;
1737507c3241Smlf 
1738507c3241Smlf 	/* read the devid */
1739507c3241Smlf 	handle = dadk_iob_alloc(DKTP_DATA, blk, NBPSCTR, KM_SLEEP);
1740507c3241Smlf 	if (handle == NULL)
1741507c3241Smlf 		goto err;
1742507c3241Smlf 
1743507c3241Smlf 	dkdevidp = (struct dk_devid *)dadk_iob_xfer(DKTP_DATA, handle, B_READ);
1744507c3241Smlf 	if (dkdevidp == NULL)
1745507c3241Smlf 		goto err;
1746507c3241Smlf 
1747507c3241Smlf 	/* Validate the revision */
1748507c3241Smlf 	if ((dkdevidp->dkd_rev_hi != DK_DEVID_REV_MSB) ||
1749507c3241Smlf 	    (dkdevidp->dkd_rev_lo != DK_DEVID_REV_LSB))
1750507c3241Smlf 		goto err;
1751507c3241Smlf 
1752507c3241Smlf 	/* Calculate the checksum */
1753507c3241Smlf 	chksum = 0;
1754507c3241Smlf 	ip = (uint_t *)dkdevidp;
1755507c3241Smlf 	for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++)
1756507c3241Smlf 		chksum ^= ip[i];
1757507c3241Smlf 	if (DKD_GETCHKSUM(dkdevidp) != chksum)
1758507c3241Smlf 		goto err;
1759507c3241Smlf 
1760507c3241Smlf 	/* Validate the device id */
1761507c3241Smlf 	if (ddi_devid_valid((ddi_devid_t)dkdevidp->dkd_devid) != DDI_SUCCESS)
1762507c3241Smlf 		goto err;
1763507c3241Smlf 
1764507c3241Smlf 	/* keep a copy of the device id */
1765507c3241Smlf 	sz = ddi_devid_sizeof((ddi_devid_t)dkdevidp->dkd_devid);
1766507c3241Smlf 	dkp->dk_devid = kmem_alloc(sz, KM_SLEEP);
1767507c3241Smlf 	bcopy(dkdevidp->dkd_devid, dkp->dk_devid, sz);
1768507c3241Smlf 
1769507c3241Smlf 	rc = DDI_SUCCESS;
1770507c3241Smlf 
1771507c3241Smlf err:
1772507c3241Smlf 	if (handle != NULL)
1773507c3241Smlf 		(void) dadk_iob_free(DKTP_DATA, handle);
1774507c3241Smlf 	return (rc);
1775507c3241Smlf }
1776507c3241Smlf 
1777507c3241Smlf /*
1778507c3241Smlf  * Create a devid and write it on the first block of the last track of
1779507c3241Smlf  * the last cylinder.
1780507c3241Smlf  * Return DDI_SUCCESS or DDI_FAILURE.
1781507c3241Smlf  */
1782507c3241Smlf static int
1783507c3241Smlf cmdk_devid_fabricate(struct cmdk *dkp)
1784507c3241Smlf {
1785507c3241Smlf 	ddi_devid_t	devid = NULL;	/* devid made by ddi_devid_init  */
1786507c3241Smlf 	struct dk_devid	*dkdevidp;	/* devid struct stored on disk */
1787507c3241Smlf 	diskaddr_t	blk;
1788507c3241Smlf 	tgdk_iob_handle	handle = NULL;
1789507c3241Smlf 	uint_t		*ip, chksum;
1790507c3241Smlf 	int		i;
17913d510deaSMark Logan 	int		rc = DDI_FAILURE;
1792507c3241Smlf 
17933d510deaSMark Logan 	if (ddi_devid_init(dkp->dk_dip, DEVID_FAB, 0, NULL, &devid) !=
17943d510deaSMark Logan 	    DDI_SUCCESS)
1795507c3241Smlf 		goto err;
1796507c3241Smlf 
1797e8fb11a1Sshidokht 	if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0)) {
1798507c3241Smlf 		/* no device id block address */
17993d510deaSMark Logan 		goto err;
1800507c3241Smlf 	}
1801507c3241Smlf 
1802507c3241Smlf 	handle = dadk_iob_alloc(DKTP_DATA, blk, NBPSCTR, KM_SLEEP);
1803507c3241Smlf 	if (!handle)
1804507c3241Smlf 		goto err;
1805507c3241Smlf 
1806507c3241Smlf 	/* Locate the buffer */
1807507c3241Smlf 	dkdevidp = (struct dk_devid *)dadk_iob_htoc(DKTP_DATA, handle);
1808507c3241Smlf 
1809507c3241Smlf 	/* Fill in the revision */
1810507c3241Smlf 	bzero(dkdevidp, NBPSCTR);
1811507c3241Smlf 	dkdevidp->dkd_rev_hi = DK_DEVID_REV_MSB;
1812507c3241Smlf 	dkdevidp->dkd_rev_lo = DK_DEVID_REV_LSB;
1813507c3241Smlf 
1814507c3241Smlf 	/* Copy in the device id */
1815507c3241Smlf 	i = ddi_devid_sizeof(devid);
1816507c3241Smlf 	if (i > DK_DEVID_SIZE)
1817507c3241Smlf 		goto err;
1818507c3241Smlf 	bcopy(devid, dkdevidp->dkd_devid, i);
1819507c3241Smlf 
1820507c3241Smlf 	/* Calculate the chksum */
1821507c3241Smlf 	chksum = 0;
1822507c3241Smlf 	ip = (uint_t *)dkdevidp;
1823507c3241Smlf 	for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++)
1824507c3241Smlf 		chksum ^= ip[i];
1825507c3241Smlf 
1826507c3241Smlf 	/* Fill in the checksum */
1827507c3241Smlf 	DKD_FORMCHKSUM(chksum, dkdevidp);
1828507c3241Smlf 
1829507c3241Smlf 	/* write the devid */
1830507c3241Smlf 	(void) dadk_iob_xfer(DKTP_DATA, handle, B_WRITE);
1831507c3241Smlf 
1832507c3241Smlf 	dkp->dk_devid = devid;
1833507c3241Smlf 
1834507c3241Smlf 	rc = DDI_SUCCESS;
1835507c3241Smlf 
1836507c3241Smlf err:
1837507c3241Smlf 	if (handle != NULL)
1838507c3241Smlf 		(void) dadk_iob_free(DKTP_DATA, handle);
1839507c3241Smlf 
1840507c3241Smlf 	if (rc != DDI_SUCCESS && devid != NULL)
1841507c3241Smlf 		ddi_devid_free(devid);
1842507c3241Smlf 
1843507c3241Smlf 	return (rc);
1844507c3241Smlf }
1845507c3241Smlf 
1846507c3241Smlf static void
1847507c3241Smlf cmdk_bbh_free_alts(struct cmdk *dkp)
1848507c3241Smlf {
1849507c3241Smlf 	if (dkp->dk_alts_hdl) {
1850507c3241Smlf 		(void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl);
1851507c3241Smlf 		kmem_free(dkp->dk_slc_cnt,
1852507c3241Smlf 		    NDKMAP * (sizeof (uint32_t) + sizeof (struct alts_ent *)));
1853507c3241Smlf 		dkp->dk_alts_hdl = NULL;
1854507c3241Smlf 	}
1855507c3241Smlf }
1856507c3241Smlf 
1857507c3241Smlf static void
1858507c3241Smlf cmdk_bbh_reopen(struct cmdk *dkp)
1859507c3241Smlf {
1860507c3241Smlf 	tgdk_iob_handle 	handle = NULL;
1861507c3241Smlf 	diskaddr_t		slcb, slcn, slce;
1862507c3241Smlf 	struct	alts_parttbl	*ap;
1863507c3241Smlf 	struct	alts_ent	*enttblp;
1864507c3241Smlf 	uint32_t		altused;
1865507c3241Smlf 	uint32_t		altbase;
1866507c3241Smlf 	uint32_t		altlast;
1867507c3241Smlf 	int			alts;
1868507c3241Smlf 	uint16_t		vtoctag;
1869507c3241Smlf 	int			i, j;
1870507c3241Smlf 
1871507c3241Smlf 	/* find slice with V_ALTSCTR tag */
1872507c3241Smlf 	for (alts = 0; alts < NDKMAP; alts++) {
1873507c3241Smlf 		if (cmlb_partinfo(
1874507c3241Smlf 		    dkp->dk_cmlbhandle,
1875507c3241Smlf 		    alts,
1876507c3241Smlf 		    &slcn,
1877507c3241Smlf 		    &slcb,
1878507c3241Smlf 		    NULL,
1879e8fb11a1Sshidokht 		    &vtoctag,
1880e8fb11a1Sshidokht 		    0)) {
1881507c3241Smlf 			goto empty;	/* no partition table exists */
1882507c3241Smlf 		}
1883507c3241Smlf 
1884507c3241Smlf 		if (vtoctag == V_ALTSCTR && slcn > 1)
1885507c3241Smlf 			break;
1886507c3241Smlf 	}
1887507c3241Smlf 	if (alts >= NDKMAP) {
1888507c3241Smlf 		goto empty;	/* no V_ALTSCTR slice defined */
1889507c3241Smlf 	}
1890507c3241Smlf 
1891507c3241Smlf 	/* read in ALTS label block */
1892507c3241Smlf 	handle = dadk_iob_alloc(DKTP_DATA, slcb, NBPSCTR, KM_SLEEP);
1893507c3241Smlf 	if (!handle) {
1894507c3241Smlf 		goto empty;
1895507c3241Smlf 	}
1896507c3241Smlf 
1897507c3241Smlf 	ap = (struct alts_parttbl *)dadk_iob_xfer(DKTP_DATA, handle, B_READ);
1898507c3241Smlf 	if (!ap || (ap->alts_sanity != ALTS_SANITY)) {
1899507c3241Smlf 		goto empty;
1900507c3241Smlf 	}
1901507c3241Smlf 
1902507c3241Smlf 	altused = ap->alts_ent_used;	/* number of BB entries */
1903507c3241Smlf 	altbase = ap->alts_ent_base;	/* blk offset from begin slice */
1904507c3241Smlf 	altlast = ap->alts_ent_end;	/* blk offset to last block */
1905507c3241Smlf 	/* ((altused * sizeof (struct alts_ent) + NBPSCTR - 1) & ~NBPSCTR) */
1906507c3241Smlf 
1907507c3241Smlf 	if (altused == 0 ||
1908507c3241Smlf 	    altbase < 1 ||
1909507c3241Smlf 	    altbase > altlast ||
1910507c3241Smlf 	    altlast >= slcn) {
1911507c3241Smlf 		goto empty;
1912507c3241Smlf 	}
1913507c3241Smlf 	(void) dadk_iob_free(DKTP_DATA, handle);
1914507c3241Smlf 
1915507c3241Smlf 	/* read in ALTS remapping table */
1916507c3241Smlf 	handle = dadk_iob_alloc(DKTP_DATA,
1917507c3241Smlf 	    slcb + altbase,
1918507c3241Smlf 	    (altlast - altbase + 1) << SCTRSHFT, KM_SLEEP);
1919507c3241Smlf 	if (!handle) {
1920507c3241Smlf 		goto empty;
1921507c3241Smlf 	}
1922507c3241Smlf 
1923507c3241Smlf 	enttblp = (struct alts_ent *)dadk_iob_xfer(DKTP_DATA, handle, B_READ);
1924507c3241Smlf 	if (!enttblp) {
1925507c3241Smlf 		goto empty;
1926507c3241Smlf 	}
1927507c3241Smlf 
1928507c3241Smlf 	rw_enter(&dkp->dk_bbh_mutex, RW_WRITER);
1929507c3241Smlf 
1930507c3241Smlf 	/* allocate space for dk_slc_cnt and dk_slc_ent tables */
1931507c3241Smlf 	if (dkp->dk_slc_cnt == NULL) {
1932507c3241Smlf 		dkp->dk_slc_cnt = kmem_alloc(NDKMAP *
1933507c3241Smlf 		    (sizeof (long) + sizeof (struct alts_ent *)), KM_SLEEP);
1934507c3241Smlf 	}
1935507c3241Smlf 	dkp->dk_slc_ent = (struct alts_ent **)(dkp->dk_slc_cnt + NDKMAP);
1936507c3241Smlf 
1937507c3241Smlf 	/* free previous BB table (if any) */
1938507c3241Smlf 	if (dkp->dk_alts_hdl) {
1939507c3241Smlf 		(void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl);
1940507c3241Smlf 		dkp->dk_alts_hdl = NULL;
1941507c3241Smlf 		dkp->dk_altused = 0;
1942507c3241Smlf 	}
1943507c3241Smlf 
1944507c3241Smlf 	/* save linkage to new BB table */
1945507c3241Smlf 	dkp->dk_alts_hdl = handle;
1946507c3241Smlf 	dkp->dk_altused = altused;
1947507c3241Smlf 
1948507c3241Smlf 	/*
1949507c3241Smlf 	 * build indexes to BB table by slice
1950507c3241Smlf 	 * effectively we have
1951507c3241Smlf 	 *	struct alts_ent *enttblp[altused];
1952507c3241Smlf 	 *
1953507c3241Smlf 	 *	uint32_t	dk_slc_cnt[NDKMAP];
1954507c3241Smlf 	 *	struct alts_ent *dk_slc_ent[NDKMAP];
1955507c3241Smlf 	 */
1956507c3241Smlf 	for (i = 0; i < NDKMAP; i++) {
1957507c3241Smlf 		if (cmlb_partinfo(
1958507c3241Smlf 		    dkp->dk_cmlbhandle,
1959507c3241Smlf 		    i,
1960507c3241Smlf 		    &slcn,
1961507c3241Smlf 		    &slcb,
1962507c3241Smlf 		    NULL,
1963e8fb11a1Sshidokht 		    NULL,
1964e8fb11a1Sshidokht 		    0)) {
1965507c3241Smlf 			goto empty1;
1966507c3241Smlf 		}
1967507c3241Smlf 
1968507c3241Smlf 		dkp->dk_slc_cnt[i] = 0;
1969507c3241Smlf 		if (slcn == 0)
1970507c3241Smlf 			continue;	/* slice is not allocated */
1971507c3241Smlf 
1972507c3241Smlf 		/* last block in slice */
1973507c3241Smlf 		slce = slcb + slcn - 1;
1974507c3241Smlf 
1975507c3241Smlf 		/* find first remap entry in after beginnning of slice */
1976507c3241Smlf 		for (j = 0; j < altused; j++) {
1977507c3241Smlf 			if (enttblp[j].bad_start + enttblp[j].bad_end >= slcb)
1978507c3241Smlf 				break;
1979507c3241Smlf 		}
1980507c3241Smlf 		dkp->dk_slc_ent[i] = enttblp + j;
1981507c3241Smlf 
1982507c3241Smlf 		/* count remap entrys until end of slice */
1983507c3241Smlf 		for (; j < altused && enttblp[j].bad_start <= slce; j++) {
1984507c3241Smlf 			dkp->dk_slc_cnt[i] += 1;
1985507c3241Smlf 		}
1986507c3241Smlf 	}
1987507c3241Smlf 
1988507c3241Smlf 	rw_exit(&dkp->dk_bbh_mutex);
1989507c3241Smlf 	return;
1990507c3241Smlf 
1991507c3241Smlf empty:
1992507c3241Smlf 	rw_enter(&dkp->dk_bbh_mutex, RW_WRITER);
1993507c3241Smlf empty1:
1994507c3241Smlf 	if (handle && handle != dkp->dk_alts_hdl)
1995507c3241Smlf 		(void) dadk_iob_free(DKTP_DATA, handle);
1996507c3241Smlf 
1997507c3241Smlf 	if (dkp->dk_alts_hdl) {
1998507c3241Smlf 		(void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl);
1999507c3241Smlf 		dkp->dk_alts_hdl = NULL;
2000507c3241Smlf 	}
2001507c3241Smlf 
2002507c3241Smlf 	rw_exit(&dkp->dk_bbh_mutex);
2003507c3241Smlf }
2004507c3241Smlf 
2005507c3241Smlf /*ARGSUSED*/
2006507c3241Smlf static bbh_cookie_t
2007507c3241Smlf cmdk_bbh_htoc(opaque_t bbh_data, opaque_t handle)
2008507c3241Smlf {
2009507c3241Smlf 	struct	bbh_handle *hp;
2010507c3241Smlf 	bbh_cookie_t ckp;
2011507c3241Smlf 
2012507c3241Smlf 	hp = (struct  bbh_handle *)handle;
2013507c3241Smlf 	ckp = hp->h_cktab + hp->h_idx;
2014507c3241Smlf 	hp->h_idx++;
2015507c3241Smlf 	return (ckp);
2016507c3241Smlf }
2017507c3241Smlf 
2018507c3241Smlf /*ARGSUSED*/
2019507c3241Smlf static void
2020507c3241Smlf cmdk_bbh_freehandle(opaque_t bbh_data, opaque_t handle)
2021507c3241Smlf {
2022507c3241Smlf 	struct	bbh_handle *hp;
2023507c3241Smlf 
2024507c3241Smlf 	hp = (struct  bbh_handle *)handle;
2025507c3241Smlf 	kmem_free(handle, (sizeof (struct bbh_handle) +
2026507c3241Smlf 	    (hp->h_totck * (sizeof (struct bbh_cookie)))));
2027507c3241Smlf }
2028507c3241Smlf 
2029507c3241Smlf 
2030507c3241Smlf /*
2031507c3241Smlf  *	cmdk_bbh_gethandle remaps the bad sectors to alternates.
2032507c3241Smlf  *	There are 7 different cases when the comparison is made
2033507c3241Smlf  *	between the bad sector cluster and the disk section.
2034507c3241Smlf  *
2035507c3241Smlf  *	bad sector cluster	gggggggggggbbbbbbbggggggggggg
2036507c3241Smlf  *	case 1:			   ddddd
2037507c3241Smlf  *	case 2:				   -d-----
2038507c3241Smlf  *	case 3:					     ddddd
2039507c3241Smlf  *	case 4:			         dddddddddddd
2040507c3241Smlf  *	case 5:			      ddddddd-----
2041507c3241Smlf  *	case 6:			           ---ddddddd
2042507c3241Smlf  *	case 7:			           ddddddd
2043507c3241Smlf  *
2044507c3241Smlf  *	where:  g = good sector,	b = bad sector
2045507c3241Smlf  *		d = sector in disk section
2046507c3241Smlf  *		- = disk section may be extended to cover those disk area
2047507c3241Smlf  */
2048507c3241Smlf 
2049507c3241Smlf static opaque_t
2050507c3241Smlf cmdk_bbh_gethandle(opaque_t bbh_data, struct buf *bp)
2051507c3241Smlf {
2052507c3241Smlf 	struct cmdk		*dkp = (struct cmdk *)bbh_data;
2053507c3241Smlf 	struct bbh_handle	*hp;
2054507c3241Smlf 	struct bbh_cookie	*ckp;
2055507c3241Smlf 	struct alts_ent		*altp;
2056507c3241Smlf 	uint32_t		alts_used;
2057507c3241Smlf 	uint32_t		part = CMDKPART(bp->b_edev);
2058507c3241Smlf 	daddr32_t		lastsec;
2059507c3241Smlf 	long			d_count;
2060507c3241Smlf 	int			i;
2061507c3241Smlf 	int			idx;
2062507c3241Smlf 	int			cnt;
2063507c3241Smlf 
2064507c3241Smlf 	if (part >= V_NUMPAR)
2065507c3241Smlf 		return (NULL);
2066507c3241Smlf 
2067507c3241Smlf 	/*
2068507c3241Smlf 	 * This if statement is atomic and it will succeed
2069507c3241Smlf 	 * if there are no bad blocks (almost always)
2070507c3241Smlf 	 *
2071507c3241Smlf 	 * so this if is performed outside of the rw_enter for speed
2072507c3241Smlf 	 * and then repeated inside the rw_enter for safety
2073507c3241Smlf 	 */
2074507c3241Smlf 	if (!dkp->dk_alts_hdl) {
2075507c3241Smlf 		return (NULL);
2076507c3241Smlf 	}
2077507c3241Smlf 
2078507c3241Smlf 	rw_enter(&dkp->dk_bbh_mutex, RW_READER);
2079507c3241Smlf 
2080507c3241Smlf 	if (dkp->dk_alts_hdl == NULL) {
2081507c3241Smlf 		rw_exit(&dkp->dk_bbh_mutex);
2082507c3241Smlf 		return (NULL);
2083507c3241Smlf 	}
2084507c3241Smlf 
2085507c3241Smlf 	alts_used = dkp->dk_slc_cnt[part];
2086507c3241Smlf 	if (alts_used == 0) {
2087507c3241Smlf 		rw_exit(&dkp->dk_bbh_mutex);
2088507c3241Smlf 		return (NULL);
2089507c3241Smlf 	}
2090507c3241Smlf 	altp = dkp->dk_slc_ent[part];
2091507c3241Smlf 
2092507c3241Smlf 	/*
2093507c3241Smlf 	 * binary search for the largest bad sector index in the alternate
2094507c3241Smlf 	 * entry table which overlaps or larger than the starting d_sec
2095507c3241Smlf 	 */
2096507c3241Smlf 	i = cmdk_bbh_bsearch(altp, alts_used, GET_BP_SEC(bp));
2097507c3241Smlf 	/* if starting sector is > the largest bad sector, return */
2098507c3241Smlf 	if (i == -1) {
2099507c3241Smlf 		rw_exit(&dkp->dk_bbh_mutex);
2100507c3241Smlf 		return (NULL);
2101507c3241Smlf 	}
2102507c3241Smlf 	/* i is the starting index.  Set altp to the starting entry addr */
2103507c3241Smlf 	altp += i;
2104507c3241Smlf 
2105507c3241Smlf 	d_count = bp->b_bcount >> SCTRSHFT;
2106507c3241Smlf 	lastsec = GET_BP_SEC(bp) + d_count - 1;
2107507c3241Smlf 
2108507c3241Smlf 	/* calculate the number of bad sectors */
2109507c3241Smlf 	for (idx = i, cnt = 0; idx < alts_used; idx++, altp++, cnt++) {
2110507c3241Smlf 		if (lastsec < altp->bad_start)
2111507c3241Smlf 			break;
2112507c3241Smlf 	}
2113507c3241Smlf 
2114507c3241Smlf 	if (!cnt) {
2115507c3241Smlf 		rw_exit(&dkp->dk_bbh_mutex);
2116507c3241Smlf 		return (NULL);
2117507c3241Smlf 	}
2118507c3241Smlf 
2119507c3241Smlf 	/* calculate the maximum number of reserved cookies */
2120507c3241Smlf 	cnt <<= 1;
2121507c3241Smlf 	cnt++;
2122507c3241Smlf 
2123507c3241Smlf 	/* allocate the handle */
2124507c3241Smlf 	hp = (struct bbh_handle *)kmem_zalloc((sizeof (*hp) +
2125507c3241Smlf 	    (cnt * sizeof (*ckp))), KM_SLEEP);
2126507c3241Smlf 
2127507c3241Smlf 	hp->h_idx = 0;
2128507c3241Smlf 	hp->h_totck = cnt;
2129507c3241Smlf 	ckp = hp->h_cktab = (struct bbh_cookie *)(hp + 1);
2130507c3241Smlf 	ckp[0].ck_sector = GET_BP_SEC(bp);
2131507c3241Smlf 	ckp[0].ck_seclen = d_count;
2132507c3241Smlf 
2133507c3241Smlf 	altp = dkp->dk_slc_ent[part];
2134507c3241Smlf 	altp += i;
2135507c3241Smlf 	for (idx = 0; i < alts_used; i++, altp++) {
2136507c3241Smlf 		/* CASE 1: */
2137507c3241Smlf 		if (lastsec < altp->bad_start)
2138507c3241Smlf 			break;
2139507c3241Smlf 
2140507c3241Smlf 		/* CASE 3: */
2141507c3241Smlf 		if (ckp[idx].ck_sector > altp->bad_end)
2142507c3241Smlf 			continue;
2143507c3241Smlf 
2144507c3241Smlf 		/* CASE 2 and 7: */
2145507c3241Smlf 		if ((ckp[idx].ck_sector >= altp->bad_start) &&
2146507c3241Smlf 		    (lastsec <= altp->bad_end)) {
2147507c3241Smlf 			ckp[idx].ck_sector = altp->good_start +
2148507c3241Smlf 			    ckp[idx].ck_sector - altp->bad_start;
2149507c3241Smlf 			break;
2150507c3241Smlf 		}
2151507c3241Smlf 
2152507c3241Smlf 		/* at least one bad sector in our section.  break it. */
2153507c3241Smlf 		/* CASE 5: */
2154507c3241Smlf 		if ((lastsec >= altp->bad_start) &&
2155507c3241Smlf 		    (lastsec <= altp->bad_end)) {
2156507c3241Smlf 			ckp[idx+1].ck_seclen = lastsec - altp->bad_start + 1;
2157507c3241Smlf 			ckp[idx].ck_seclen -= ckp[idx+1].ck_seclen;
2158507c3241Smlf 			ckp[idx+1].ck_sector = altp->good_start;
2159507c3241Smlf 			break;
2160507c3241Smlf 		}
2161507c3241Smlf 		/* CASE 6: */
2162507c3241Smlf 		if ((ckp[idx].ck_sector <= altp->bad_end) &&
2163507c3241Smlf 		    (ckp[idx].ck_sector >= altp->bad_start)) {
2164507c3241Smlf 			ckp[idx+1].ck_seclen = ckp[idx].ck_seclen;
2165507c3241Smlf 			ckp[idx].ck_seclen = altp->bad_end -
2166507c3241Smlf 			    ckp[idx].ck_sector + 1;
2167507c3241Smlf 			ckp[idx+1].ck_seclen -= ckp[idx].ck_seclen;
2168507c3241Smlf 			ckp[idx].ck_sector = altp->good_start +
2169507c3241Smlf 			    ckp[idx].ck_sector - altp->bad_start;
2170507c3241Smlf 			idx++;
2171507c3241Smlf 			ckp[idx].ck_sector = altp->bad_end + 1;
2172507c3241Smlf 			continue;	/* check rest of section */
2173507c3241Smlf 		}
2174507c3241Smlf 
2175507c3241Smlf 		/* CASE 4: */
2176507c3241Smlf 		ckp[idx].ck_seclen = altp->bad_start - ckp[idx].ck_sector;
2177507c3241Smlf 		ckp[idx+1].ck_sector = altp->good_start;
2178507c3241Smlf 		ckp[idx+1].ck_seclen = altp->bad_end - altp->bad_start + 1;
2179507c3241Smlf 		idx += 2;
2180507c3241Smlf 		ckp[idx].ck_sector = altp->bad_end + 1;
2181507c3241Smlf 		ckp[idx].ck_seclen = lastsec - altp->bad_end;
2182507c3241Smlf 	}
2183507c3241Smlf 
2184507c3241Smlf 	rw_exit(&dkp->dk_bbh_mutex);
2185507c3241Smlf 	return ((opaque_t)hp);
2186507c3241Smlf }
2187507c3241Smlf 
2188507c3241Smlf static int
2189507c3241Smlf cmdk_bbh_bsearch(struct alts_ent *buf, int cnt, daddr32_t key)
2190507c3241Smlf {
2191507c3241Smlf 	int	i;
2192507c3241Smlf 	int	ind;
2193507c3241Smlf 	int	interval;
2194507c3241Smlf 	int	mystatus = -1;
2195507c3241Smlf 
2196507c3241Smlf 	if (!cnt)
2197507c3241Smlf 		return (mystatus);
2198507c3241Smlf 
2199507c3241Smlf 	ind = 1; /* compiler complains about possible uninitialized var	*/
2200507c3241Smlf 	for (i = 1; i <= cnt; i <<= 1)
2201507c3241Smlf 		ind = i;
2202507c3241Smlf 
2203507c3241Smlf 	for (interval = ind; interval; ) {
2204507c3241Smlf 		if ((key >= buf[ind-1].bad_start) &&
2205507c3241Smlf 		    (key <= buf[ind-1].bad_end)) {
2206507c3241Smlf 			return (ind-1);
2207507c3241Smlf 		} else {
2208507c3241Smlf 			interval >>= 1;
2209507c3241Smlf 			if (key < buf[ind-1].bad_start) {
2210507c3241Smlf 				/* record the largest bad sector index */
2211507c3241Smlf 				mystatus = ind-1;
2212507c3241Smlf 				if (!interval)
2213507c3241Smlf 					break;
2214507c3241Smlf 				ind = ind - interval;
2215507c3241Smlf 			} else {
2216507c3241Smlf 				/*
2217507c3241Smlf 				 * if key is larger than the last element
2218507c3241Smlf 				 * then break
2219507c3241Smlf 				 */
2220507c3241Smlf 				if ((ind == cnt) || !interval)
2221507c3241Smlf 					break;
2222507c3241Smlf 				if ((ind+interval) <= cnt)
2223507c3241Smlf 					ind += interval;
2224507c3241Smlf 			}
2225507c3241Smlf 		}
2226507c3241Smlf 	}
2227507c3241Smlf 	return (mystatus);
2228507c3241Smlf }
2229