1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26/*
27 * Copyright (c) 2018, Joyent, Inc.
28 */
29
30#include <sys/scsi/scsi.h>
31#include <sys/dktp/cm.h>
32#include <sys/dktp/quetypes.h>
33#include <sys/dktp/queue.h>
34#include <sys/dktp/fctypes.h>
35#include <sys/dktp/flowctrl.h>
36#include <sys/dktp/cmdev.h>
37#include <sys/dkio.h>
38#include <sys/dktp/tgdk.h>
39#include <sys/dktp/dadk.h>
40#include <sys/dktp/bbh.h>
41#include <sys/dktp/altsctr.h>
42#include <sys/dktp/cmdk.h>
43
44#include <sys/stat.h>
45#include <sys/vtoc.h>
46#include <sys/file.h>
47#include <sys/dktp/dadkio.h>
48#include <sys/aio_req.h>
49
50#include <sys/cmlb.h>
51
52/*
53 * Local Static Data
54 */
55#ifdef CMDK_DEBUG
56#define	DENT	0x0001
57#define	DIO	0x0002
58
59static	int	cmdk_debug = DIO;
60#endif
61
62#ifndef	TRUE
63#define	TRUE	1
64#endif
65
66#ifndef	FALSE
67#define	FALSE	0
68#endif
69
70/*
71 * NDKMAP is the base number for accessing the fdisk partitions.
72 * c?d?p0 --> cmdk@?,?:q
73 */
74#define	PARTITION0_INDEX	(NDKMAP + 0)
75
76#define	DKTP_DATA		(dkp->dk_tgobjp)->tg_data
77#define	DKTP_EXT		(dkp->dk_tgobjp)->tg_ext
78
79void *cmdk_state;
80
81/*
82 * the cmdk_attach_mutex protects cmdk_max_instance in multi-threaded
83 * attach situations
84 */
85static kmutex_t cmdk_attach_mutex;
86static int cmdk_max_instance = 0;
87
88/*
89 * Panic dumpsys state
90 * There is only a single flag that is not mutex locked since
91 * the system is prevented from thread switching and cmdk_dump
92 * will only be called in a single threaded operation.
93 */
94static int	cmdk_indump;
95
96/*
97 * Local Function Prototypes
98 */
99static int cmdk_create_obj(dev_info_t *dip, struct cmdk *dkp);
100static void cmdk_destroy_obj(dev_info_t *dip, struct cmdk *dkp);
101static void cmdkmin(struct buf *bp);
102static int cmdkrw(dev_t dev, struct uio *uio, int flag);
103static int cmdkarw(dev_t dev, struct aio_req *aio, int flag);
104
105/*
106 * Bad Block Handling Functions Prototypes
107 */
108static void cmdk_bbh_reopen(struct cmdk *dkp);
109static opaque_t cmdk_bbh_gethandle(opaque_t bbh_data, struct buf *bp);
110static bbh_cookie_t cmdk_bbh_htoc(opaque_t bbh_data, opaque_t handle);
111static void cmdk_bbh_freehandle(opaque_t bbh_data, opaque_t handle);
112static void cmdk_bbh_close(struct cmdk *dkp);
113static void cmdk_bbh_setalts_idx(struct cmdk *dkp);
114static int cmdk_bbh_bsearch(struct alts_ent *buf, int cnt, daddr32_t key);
115
116static struct bbh_objops cmdk_bbh_ops = {
117	nulldev,
118	nulldev,
119	cmdk_bbh_gethandle,
120	cmdk_bbh_htoc,
121	cmdk_bbh_freehandle,
122	0, 0
123};
124
125static int cmdkopen(dev_t *dev_p, int flag, int otyp, cred_t *credp);
126static int cmdkclose(dev_t dev, int flag, int otyp, cred_t *credp);
127static int cmdkstrategy(struct buf *bp);
128static int cmdkdump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk);
129static int cmdkioctl(dev_t, int, intptr_t, int, cred_t *, int *);
130static int cmdkread(dev_t dev, struct uio *uio, cred_t *credp);
131static int cmdkwrite(dev_t dev, struct uio *uio, cred_t *credp);
132static int cmdk_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
133    int mod_flags, char *name, caddr_t valuep, int *lengthp);
134static int cmdkaread(dev_t dev, struct aio_req *aio, cred_t *credp);
135static int cmdkawrite(dev_t dev, struct aio_req *aio, cred_t *credp);
136
137/*
138 * Device driver ops vector
139 */
140
141static struct cb_ops cmdk_cb_ops = {
142	cmdkopen, 		/* open */
143	cmdkclose, 		/* close */
144	cmdkstrategy, 		/* strategy */
145	nodev, 			/* print */
146	cmdkdump, 		/* dump */
147	cmdkread, 		/* read */
148	cmdkwrite, 		/* write */
149	cmdkioctl, 		/* ioctl */
150	nodev, 			/* devmap */
151	nodev, 			/* mmap */
152	nodev, 			/* segmap */
153	nochpoll, 		/* poll */
154	cmdk_prop_op, 		/* cb_prop_op */
155	0, 			/* streamtab  */
156	D_64BIT | D_MP | D_NEW,	/* Driver comaptibility flag */
157	CB_REV,			/* cb_rev */
158	cmdkaread,		/* async read */
159	cmdkawrite		/* async write */
160};
161
162static int cmdkinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
163    void **result);
164static int cmdkprobe(dev_info_t *dip);
165static int cmdkattach(dev_info_t *dip, ddi_attach_cmd_t cmd);
166static int cmdkdetach(dev_info_t *dip, ddi_detach_cmd_t cmd);
167
168static void cmdk_setup_pm(dev_info_t *dip, struct cmdk *dkp);
169static int cmdkresume(dev_info_t *dip);
170static int cmdksuspend(dev_info_t *dip);
171static int cmdkpower(dev_info_t *dip, int component, int level);
172
173struct dev_ops cmdk_ops = {
174	DEVO_REV, 		/* devo_rev, */
175	0, 			/* refcnt  */
176	cmdkinfo,		/* info */
177	nulldev, 		/* identify */
178	cmdkprobe, 		/* probe */
179	cmdkattach, 		/* attach */
180	cmdkdetach,		/* detach */
181	nodev, 			/* reset */
182	&cmdk_cb_ops, 		/* driver operations */
183	(struct bus_ops *)0,	/* bus operations */
184	cmdkpower,		/* power */
185	ddi_quiesce_not_needed,	/* quiesce */
186};
187
188/*
189 * This is the loadable module wrapper.
190 */
191#include <sys/modctl.h>
192
193static struct modldrv modldrv = {
194	&mod_driverops,		/* Type of module. This one is a driver */
195	"Common Direct Access Disk",
196	&cmdk_ops,				/* driver ops 		*/
197};
198
199static struct modlinkage modlinkage = {
200	MODREV_1, (void *)&modldrv, NULL
201};
202
203/* Function prototypes for cmlb callbacks */
204
205static int cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr,
206    diskaddr_t start, size_t length, void *tg_cookie);
207
208static int cmdk_lb_getinfo(dev_info_t *dip, int cmd,  void *arg,
209    void *tg_cookie);
210
211static void cmdk_devid_setup(struct cmdk *dkp);
212static int cmdk_devid_modser(struct cmdk *dkp);
213static int cmdk_get_modser(struct cmdk *dkp, int ioccmd, char *buf, int len);
214static int cmdk_devid_fabricate(struct cmdk *dkp);
215static int cmdk_devid_read(struct cmdk *dkp);
216
217static cmlb_tg_ops_t cmdk_lb_ops = {
218	TG_DK_OPS_VERSION_1,
219	cmdk_lb_rdwr,
220	cmdk_lb_getinfo
221};
222
223static boolean_t
224cmdk_isopen(struct cmdk *dkp, dev_t dev)
225{
226	int		part, otyp;
227	ulong_t		partbit;
228
229	ASSERT(MUTEX_HELD((&dkp->dk_mutex)));
230
231	part = CMDKPART(dev);
232	partbit = 1 << part;
233
234	/* account for close */
235	if (dkp->dk_open_lyr[part] != 0)
236		return (B_TRUE);
237	for (otyp = 0; otyp < OTYPCNT; otyp++)
238		if (dkp->dk_open_reg[otyp] & partbit)
239			return (B_TRUE);
240	return (B_FALSE);
241}
242
243int
244_init(void)
245{
246	int 	rval;
247
248	if (rval = ddi_soft_state_init(&cmdk_state, sizeof (struct cmdk), 7))
249		return (rval);
250
251	mutex_init(&cmdk_attach_mutex, NULL, MUTEX_DRIVER, NULL);
252	if ((rval = mod_install(&modlinkage)) != 0) {
253		mutex_destroy(&cmdk_attach_mutex);
254		ddi_soft_state_fini(&cmdk_state);
255	}
256	return (rval);
257}
258
259int
260_fini(void)
261{
262	return (EBUSY);
263}
264
265int
266_info(struct modinfo *modinfop)
267{
268	return (mod_info(&modlinkage, modinfop));
269}
270
271/*
272 * Autoconfiguration Routines
273 */
274static int
275cmdkprobe(dev_info_t *dip)
276{
277	int 	instance;
278	int	status;
279	struct	cmdk	*dkp;
280
281	instance = ddi_get_instance(dip);
282
283	if (ddi_get_soft_state(cmdk_state, instance))
284		return (DDI_PROBE_PARTIAL);
285
286	if (ddi_soft_state_zalloc(cmdk_state, instance) != DDI_SUCCESS)
287		return (DDI_PROBE_PARTIAL);
288
289	if ((dkp = ddi_get_soft_state(cmdk_state, instance)) == NULL)
290		return (DDI_PROBE_PARTIAL);
291
292	mutex_init(&dkp->dk_mutex, NULL, MUTEX_DRIVER, NULL);
293	rw_init(&dkp->dk_bbh_mutex, NULL, RW_DRIVER, NULL);
294	dkp->dk_dip = dip;
295	mutex_enter(&dkp->dk_mutex);
296
297	dkp->dk_dev = makedevice(ddi_driver_major(dip),
298	    ddi_get_instance(dip) << CMDK_UNITSHF);
299
300	/* linkage to dadk and strategy */
301	if (cmdk_create_obj(dip, dkp) != DDI_SUCCESS) {
302		mutex_exit(&dkp->dk_mutex);
303		mutex_destroy(&dkp->dk_mutex);
304		rw_destroy(&dkp->dk_bbh_mutex);
305		ddi_soft_state_free(cmdk_state, instance);
306		return (DDI_PROBE_PARTIAL);
307	}
308
309	status = dadk_probe(DKTP_DATA, KM_NOSLEEP);
310	if (status != DDI_PROBE_SUCCESS) {
311		cmdk_destroy_obj(dip, dkp);	/* dadk/strategy linkage  */
312		mutex_exit(&dkp->dk_mutex);
313		mutex_destroy(&dkp->dk_mutex);
314		rw_destroy(&dkp->dk_bbh_mutex);
315		ddi_soft_state_free(cmdk_state, instance);
316		return (status);
317	}
318
319	mutex_exit(&dkp->dk_mutex);
320#ifdef CMDK_DEBUG
321	if (cmdk_debug & DENT)
322		PRF("cmdkprobe: instance= %d name= `%s`\n",
323		    instance, ddi_get_name_addr(dip));
324#endif
325	return (status);
326}
327
328static int
329cmdkattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
330{
331	int 		instance;
332	struct		cmdk *dkp;
333	char 		*node_type;
334
335	switch (cmd) {
336	case DDI_ATTACH:
337		break;
338	case DDI_RESUME:
339		return (cmdkresume(dip));
340	default:
341		return (DDI_FAILURE);
342	}
343
344	instance = ddi_get_instance(dip);
345	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
346		return (DDI_FAILURE);
347
348	dkp->dk_pm_level = CMDK_SPINDLE_UNINIT;
349	mutex_init(&dkp->dk_mutex, NULL, MUTEX_DRIVER, NULL);
350
351	mutex_enter(&dkp->dk_mutex);
352
353	/* dadk_attach is an empty function that only returns SUCCESS */
354	(void) dadk_attach(DKTP_DATA);
355
356	node_type = (DKTP_EXT->tg_nodetype);
357
358	/*
359	 * this open allows cmlb to read the device
360	 * and determine the label types
361	 * so that cmlb can create minor nodes for device
362	 */
363
364	/* open the target disk	 */
365	if (dadk_open(DKTP_DATA, 0) != DDI_SUCCESS)
366		goto fail2;
367
368#ifdef _ILP32
369	{
370		struct  tgdk_geom phyg;
371		(void) dadk_getphygeom(DKTP_DATA, &phyg);
372		if ((phyg.g_cap - 1) > DK_MAX_BLOCKS) {
373			(void) dadk_close(DKTP_DATA);
374			goto fail2;
375		}
376	}
377#endif
378
379
380	/* mark as having opened target */
381	dkp->dk_flag |= CMDK_TGDK_OPEN;
382
383	cmlb_alloc_handle((cmlb_handle_t *)&dkp->dk_cmlbhandle);
384
385	if (cmlb_attach(dip,
386	    &cmdk_lb_ops,
387	    DTYPE_DIRECT,		/* device_type */
388	    B_FALSE,			/* removable */
389	    B_FALSE,			/* hot pluggable XXX */
390	    node_type,
391	    CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT,	/* alter_behaviour */
392	    dkp->dk_cmlbhandle,
393	    0) != 0)
394		goto fail1;
395
396	/* Calling validate will create minor nodes according to disk label */
397	(void) cmlb_validate(dkp->dk_cmlbhandle, 0, 0);
398
399	/* set bbh (Bad Block Handling) */
400	cmdk_bbh_reopen(dkp);
401
402	/* setup devid string */
403	cmdk_devid_setup(dkp);
404
405	mutex_enter(&cmdk_attach_mutex);
406	if (instance > cmdk_max_instance)
407		cmdk_max_instance = instance;
408	mutex_exit(&cmdk_attach_mutex);
409
410	mutex_exit(&dkp->dk_mutex);
411
412	/*
413	 * Add a zero-length attribute to tell the world we support
414	 * kernel ioctls (for layered drivers)
415	 */
416	(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
417	    DDI_KERNEL_IOCTL, NULL, 0);
418	ddi_report_dev(dip);
419
420	/*
421	 * Initialize power management
422	 */
423	mutex_init(&dkp->dk_pm_mutex, NULL, MUTEX_DRIVER, NULL);
424	cv_init(&dkp->dk_suspend_cv,   NULL, CV_DRIVER, NULL);
425	cmdk_setup_pm(dip, dkp);
426
427	return (DDI_SUCCESS);
428
429fail1:
430	cmlb_free_handle(&dkp->dk_cmlbhandle);
431	(void) dadk_close(DKTP_DATA);
432fail2:
433	cmdk_destroy_obj(dip, dkp);
434	rw_destroy(&dkp->dk_bbh_mutex);
435	mutex_exit(&dkp->dk_mutex);
436	mutex_destroy(&dkp->dk_mutex);
437	ddi_soft_state_free(cmdk_state, instance);
438	return (DDI_FAILURE);
439}
440
441
442static int
443cmdkdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
444{
445	struct cmdk	*dkp;
446	int 		instance;
447	int		max_instance;
448
449	switch (cmd) {
450	case DDI_DETACH:
451		/* return (DDI_FAILURE); */
452		break;
453	case DDI_SUSPEND:
454		return (cmdksuspend(dip));
455	default:
456#ifdef CMDK_DEBUG
457		if (cmdk_debug & DIO) {
458			PRF("cmdkdetach: cmd = %d unknown\n", cmd);
459		}
460#endif
461		return (DDI_FAILURE);
462	}
463
464	mutex_enter(&cmdk_attach_mutex);
465	max_instance = cmdk_max_instance;
466	mutex_exit(&cmdk_attach_mutex);
467
468	/* check if any instance of driver is open */
469	for (instance = 0; instance < max_instance; instance++) {
470		dkp = ddi_get_soft_state(cmdk_state, instance);
471		if (!dkp)
472			continue;
473		if (dkp->dk_flag & CMDK_OPEN)
474			return (DDI_FAILURE);
475	}
476
477	instance = ddi_get_instance(dip);
478	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
479		return (DDI_SUCCESS);
480
481	mutex_enter(&dkp->dk_mutex);
482
483	/*
484	 * The cmdk_part_info call at the end of cmdkattach may have
485	 * caused cmdk_reopen to do a TGDK_OPEN, make sure we close on
486	 * detach for case when cmdkopen/cmdkclose never occurs.
487	 */
488	if (dkp->dk_flag & CMDK_TGDK_OPEN) {
489		dkp->dk_flag &= ~CMDK_TGDK_OPEN;
490		(void) dadk_close(DKTP_DATA);
491	}
492
493	cmlb_detach(dkp->dk_cmlbhandle, 0);
494	cmlb_free_handle(&dkp->dk_cmlbhandle);
495	ddi_prop_remove_all(dip);
496
497	cmdk_destroy_obj(dip, dkp);	/* dadk/strategy linkage  */
498
499	/*
500	 * free the devid structure if allocated before
501	 */
502	if (dkp->dk_devid) {
503		ddi_devid_free(dkp->dk_devid);
504		dkp->dk_devid = NULL;
505	}
506
507	mutex_exit(&dkp->dk_mutex);
508	mutex_destroy(&dkp->dk_mutex);
509	rw_destroy(&dkp->dk_bbh_mutex);
510	mutex_destroy(&dkp->dk_pm_mutex);
511	cv_destroy(&dkp->dk_suspend_cv);
512	ddi_soft_state_free(cmdk_state, instance);
513
514	return (DDI_SUCCESS);
515}
516
517static int
518cmdkinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
519{
520	dev_t		dev = (dev_t)arg;
521	int 		instance;
522	struct	cmdk	*dkp;
523
524#ifdef lint
525	dip = dip;	/* no one ever uses this */
526#endif
527#ifdef CMDK_DEBUG
528	if (cmdk_debug & DENT)
529		PRF("cmdkinfo: call\n");
530#endif
531	instance = CMDKUNIT(dev);
532
533	switch (infocmd) {
534		case DDI_INFO_DEVT2DEVINFO:
535			if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
536				return (DDI_FAILURE);
537			*result = (void *) dkp->dk_dip;
538			break;
539		case DDI_INFO_DEVT2INSTANCE:
540			*result = (void *)(intptr_t)instance;
541			break;
542		default:
543			return (DDI_FAILURE);
544	}
545	return (DDI_SUCCESS);
546}
547
548/*
549 * Initialize the power management components
550 */
551static void
552cmdk_setup_pm(dev_info_t *dip, struct cmdk *dkp)
553{
554	char *pm_comp[] = { "NAME=cmdk", "0=off", "1=on", NULL };
555
556	/*
557	 * Since the cmdk device does not the 'reg' property,
558	 * cpr will not call its DDI_SUSPEND/DDI_RESUME entries.
559	 * The following code is to tell cpr that this device
560	 * DOES need to be suspended and resumed.
561	 */
562	(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
563	    "pm-hardware-state", "needs-suspend-resume");
564
565	if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
566	    "pm-components", pm_comp, 3) == DDI_PROP_SUCCESS) {
567		if (pm_raise_power(dip, 0, CMDK_SPINDLE_ON) == DDI_SUCCESS) {
568			mutex_enter(&dkp->dk_pm_mutex);
569			dkp->dk_pm_level = CMDK_SPINDLE_ON;
570			dkp->dk_pm_is_enabled = 1;
571			mutex_exit(&dkp->dk_pm_mutex);
572		} else {
573			mutex_enter(&dkp->dk_pm_mutex);
574			dkp->dk_pm_level = CMDK_SPINDLE_OFF;
575			dkp->dk_pm_is_enabled = 0;
576			mutex_exit(&dkp->dk_pm_mutex);
577		}
578	} else {
579		mutex_enter(&dkp->dk_pm_mutex);
580		dkp->dk_pm_level = CMDK_SPINDLE_UNINIT;
581		dkp->dk_pm_is_enabled = 0;
582		mutex_exit(&dkp->dk_pm_mutex);
583	}
584}
585
586/*
587 * suspend routine, it will be run when get the command
588 * DDI_SUSPEND at detach(9E) from system power management
589 */
590static int
591cmdksuspend(dev_info_t *dip)
592{
593	struct cmdk	*dkp;
594	int		instance;
595	clock_t		count = 0;
596
597	instance = ddi_get_instance(dip);
598	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
599		return (DDI_FAILURE);
600	mutex_enter(&dkp->dk_mutex);
601	if (dkp->dk_flag & CMDK_SUSPEND) {
602		mutex_exit(&dkp->dk_mutex);
603		return (DDI_SUCCESS);
604	}
605	dkp->dk_flag |= CMDK_SUSPEND;
606
607	/* need to wait a while */
608	while (dadk_getcmds(DKTP_DATA) != 0) {
609		delay(drv_usectohz(1000000));
610		if (count > 60) {
611			dkp->dk_flag &= ~CMDK_SUSPEND;
612			cv_broadcast(&dkp->dk_suspend_cv);
613			mutex_exit(&dkp->dk_mutex);
614			return (DDI_FAILURE);
615		}
616		count++;
617	}
618	mutex_exit(&dkp->dk_mutex);
619	return (DDI_SUCCESS);
620}
621
622/*
623 * resume routine, it will be run when get the command
624 * DDI_RESUME at attach(9E) from system power management
625 */
626static int
627cmdkresume(dev_info_t *dip)
628{
629	struct cmdk	*dkp;
630	int		instance;
631
632	instance = ddi_get_instance(dip);
633	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
634		return (DDI_FAILURE);
635	mutex_enter(&dkp->dk_mutex);
636	if (!(dkp->dk_flag & CMDK_SUSPEND)) {
637		mutex_exit(&dkp->dk_mutex);
638		return (DDI_FAILURE);
639	}
640	dkp->dk_pm_level = CMDK_SPINDLE_ON;
641	dkp->dk_flag &= ~CMDK_SUSPEND;
642	cv_broadcast(&dkp->dk_suspend_cv);
643	mutex_exit(&dkp->dk_mutex);
644	return (DDI_SUCCESS);
645
646}
647
648/*
649 * power management entry point, it was used to
650 * change power management component.
651 * Actually, the real hard drive suspend/resume
652 * was handled in ata, so this function is not
653 * doing any real work other than verifying that
654 * the disk is idle.
655 */
656static int
657cmdkpower(dev_info_t *dip, int component, int level)
658{
659	struct cmdk	*dkp;
660	int		instance;
661
662	instance = ddi_get_instance(dip);
663	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) ||
664	    component != 0 || level > CMDK_SPINDLE_ON ||
665	    level < CMDK_SPINDLE_OFF) {
666		return (DDI_FAILURE);
667	}
668
669	mutex_enter(&dkp->dk_pm_mutex);
670	if (dkp->dk_pm_is_enabled && dkp->dk_pm_level == level) {
671		mutex_exit(&dkp->dk_pm_mutex);
672		return (DDI_SUCCESS);
673	}
674	mutex_exit(&dkp->dk_pm_mutex);
675
676	if ((level == CMDK_SPINDLE_OFF) &&
677	    (dadk_getcmds(DKTP_DATA) != 0)) {
678		return (DDI_FAILURE);
679	}
680
681	mutex_enter(&dkp->dk_pm_mutex);
682	dkp->dk_pm_level = level;
683	mutex_exit(&dkp->dk_pm_mutex);
684	return (DDI_SUCCESS);
685}
686
687static int
688cmdk_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
689    char *name, caddr_t valuep, int *lengthp)
690{
691	struct	cmdk	*dkp;
692
693#ifdef CMDK_DEBUG
694	if (cmdk_debug & DENT)
695		PRF("cmdk_prop_op: call\n");
696#endif
697
698	dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip));
699	if (dkp == NULL)
700		return (ddi_prop_op(dev, dip, prop_op, mod_flags,
701		    name, valuep, lengthp));
702
703	return (cmlb_prop_op(dkp->dk_cmlbhandle,
704	    dev, dip, prop_op, mod_flags, name, valuep, lengthp,
705	    CMDKPART(dev), NULL));
706}
707
708/*
709 * dump routine
710 */
711static int
712cmdkdump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk)
713{
714	int 		instance;
715	struct	cmdk	*dkp;
716	diskaddr_t	p_lblksrt;
717	diskaddr_t	p_lblkcnt;
718	struct	buf	local;
719	struct	buf	*bp;
720
721#ifdef CMDK_DEBUG
722	if (cmdk_debug & DENT)
723		PRF("cmdkdump: call\n");
724#endif
725	instance = CMDKUNIT(dev);
726	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) || (blkno < 0))
727		return (ENXIO);
728
729	if (cmlb_partinfo(
730	    dkp->dk_cmlbhandle,
731	    CMDKPART(dev),
732	    &p_lblkcnt,
733	    &p_lblksrt,
734	    NULL,
735	    NULL,
736	    0)) {
737		return (ENXIO);
738	}
739
740	if ((blkno+nblk) > p_lblkcnt)
741		return (EINVAL);
742
743	cmdk_indump = 1;	/* Tell disk targets we are panic dumpping */
744
745	bp = &local;
746	bzero(bp, sizeof (*bp));
747	bp->b_flags = B_BUSY;
748	bp->b_un.b_addr = addr;
749	bp->b_bcount = nblk << SCTRSHFT;
750	SET_BP_SEC(bp, ((ulong_t)(p_lblksrt + blkno)));
751
752	(void) dadk_dump(DKTP_DATA, bp);
753	return (bp->b_error);
754}
755
756/*
757 * Copy in the dadkio_rwcmd according to the user's data model.  If needed,
758 * convert it for our internal use.
759 */
760static int
761rwcmd_copyin(struct dadkio_rwcmd *rwcmdp, caddr_t inaddr, int flag)
762{
763	switch (ddi_model_convert_from(flag)) {
764		case DDI_MODEL_ILP32: {
765			struct dadkio_rwcmd32 cmd32;
766
767			if (ddi_copyin(inaddr, &cmd32,
768			    sizeof (struct dadkio_rwcmd32), flag)) {
769				return (EFAULT);
770			}
771
772			rwcmdp->cmd = cmd32.cmd;
773			rwcmdp->flags = cmd32.flags;
774			rwcmdp->blkaddr = (blkaddr_t)cmd32.blkaddr;
775			rwcmdp->buflen = cmd32.buflen;
776			rwcmdp->bufaddr = (caddr_t)(intptr_t)cmd32.bufaddr;
777			/*
778			 * Note: we do not convert the 'status' field,
779			 * as it should not contain valid data at this
780			 * point.
781			 */
782			bzero(&rwcmdp->status, sizeof (rwcmdp->status));
783			break;
784		}
785		case DDI_MODEL_NONE: {
786			if (ddi_copyin(inaddr, rwcmdp,
787			    sizeof (struct dadkio_rwcmd), flag)) {
788				return (EFAULT);
789			}
790		}
791	}
792	return (0);
793}
794
795/*
796 * If necessary, convert the internal rwcmdp and status to the appropriate
797 * data model and copy it out to the user.
798 */
799static int
800rwcmd_copyout(struct dadkio_rwcmd *rwcmdp, caddr_t outaddr, int flag)
801{
802	switch (ddi_model_convert_from(flag)) {
803		case DDI_MODEL_ILP32: {
804			struct dadkio_rwcmd32 cmd32;
805
806			cmd32.cmd = rwcmdp->cmd;
807			cmd32.flags = rwcmdp->flags;
808			cmd32.blkaddr = rwcmdp->blkaddr;
809			cmd32.buflen = rwcmdp->buflen;
810			ASSERT64(((uintptr_t)rwcmdp->bufaddr >> 32) == 0);
811			cmd32.bufaddr = (caddr32_t)(uintptr_t)rwcmdp->bufaddr;
812
813			cmd32.status.status = rwcmdp->status.status;
814			cmd32.status.resid = rwcmdp->status.resid;
815			cmd32.status.failed_blk_is_valid =
816			    rwcmdp->status.failed_blk_is_valid;
817			cmd32.status.failed_blk = rwcmdp->status.failed_blk;
818			cmd32.status.fru_code_is_valid =
819			    rwcmdp->status.fru_code_is_valid;
820			cmd32.status.fru_code = rwcmdp->status.fru_code;
821
822			bcopy(rwcmdp->status.add_error_info,
823			    cmd32.status.add_error_info, DADKIO_ERROR_INFO_LEN);
824
825			if (ddi_copyout(&cmd32, outaddr,
826			    sizeof (struct dadkio_rwcmd32), flag))
827				return (EFAULT);
828			break;
829		}
830		case DDI_MODEL_NONE: {
831			if (ddi_copyout(rwcmdp, outaddr,
832			    sizeof (struct dadkio_rwcmd), flag))
833				return (EFAULT);
834		}
835	}
836	return (0);
837}
838
839/*
840 * ioctl routine
841 */
842static int
843cmdkioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp)
844{
845	int 		instance;
846	struct scsi_device *devp;
847	struct cmdk	*dkp;
848	char 		data[NBPSCTR];
849
850	instance = CMDKUNIT(dev);
851	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
852		return (ENXIO);
853
854	mutex_enter(&dkp->dk_mutex);
855	while (dkp->dk_flag & CMDK_SUSPEND) {
856		cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
857	}
858	mutex_exit(&dkp->dk_mutex);
859
860	bzero(data, sizeof (data));
861
862	switch (cmd) {
863
864	case DKIOCGMEDIAINFO: {
865		struct dk_minfo	media_info;
866		struct  tgdk_geom phyg;
867
868		/* dadk_getphygeom always returns success */
869		(void) dadk_getphygeom(DKTP_DATA, &phyg);
870
871		media_info.dki_lbsize = phyg.g_secsiz;
872		media_info.dki_capacity = phyg.g_cap;
873		media_info.dki_media_type = DK_FIXED_DISK;
874
875		if (ddi_copyout(&media_info, (void *)arg,
876		    sizeof (struct dk_minfo), flag)) {
877			return (EFAULT);
878		} else {
879			return (0);
880		}
881	}
882
883	case DKIOCINFO: {
884		struct dk_cinfo *info = (struct dk_cinfo *)data;
885
886		/* controller information */
887		info->dki_ctype = (DKTP_EXT->tg_ctype);
888		info->dki_cnum = ddi_get_instance(ddi_get_parent(dkp->dk_dip));
889		(void) strcpy(info->dki_cname,
890		    ddi_get_name(ddi_get_parent(dkp->dk_dip)));
891
892		/* Unit Information */
893		info->dki_unit = ddi_get_instance(dkp->dk_dip);
894		devp = ddi_get_driver_private(dkp->dk_dip);
895		info->dki_slave = (CMDEV_TARG(devp)<<3) | CMDEV_LUN(devp);
896		(void) strcpy(info->dki_dname, ddi_driver_name(dkp->dk_dip));
897		info->dki_flags = DKI_FMTVOL;
898		info->dki_partition = CMDKPART(dev);
899
900		info->dki_maxtransfer = maxphys / DEV_BSIZE;
901		info->dki_addr = 1;
902		info->dki_space = 0;
903		info->dki_prio = 0;
904		info->dki_vec = 0;
905
906		if (ddi_copyout(data, (void *)arg, sizeof (*info), flag))
907			return (EFAULT);
908		else
909			return (0);
910	}
911
912	case DKIOCSTATE: {
913		int	state;
914		int	rval;
915		diskaddr_t	p_lblksrt;
916		diskaddr_t	p_lblkcnt;
917
918		if (ddi_copyin((void *)arg, &state, sizeof (int), flag))
919			return (EFAULT);
920
921		/* dadk_check_media blocks until state changes */
922		if (rval = dadk_check_media(DKTP_DATA, &state))
923			return (rval);
924
925		if (state == DKIO_INSERTED) {
926
927			if (cmlb_validate(dkp->dk_cmlbhandle, 0, 0) != 0)
928				return (ENXIO);
929
930			if (cmlb_partinfo(dkp->dk_cmlbhandle, CMDKPART(dev),
931			    &p_lblkcnt, &p_lblksrt, NULL, NULL, 0))
932				return (ENXIO);
933
934			if (p_lblkcnt <= 0)
935				return (ENXIO);
936		}
937
938		if (ddi_copyout(&state, (caddr_t)arg, sizeof (int), flag))
939			return (EFAULT);
940
941		return (0);
942	}
943
944	/*
945	 * is media removable?
946	 */
947	case DKIOCREMOVABLE: {
948		int i;
949
950		i = (DKTP_EXT->tg_rmb) ? 1 : 0;
951
952		if (ddi_copyout(&i, (caddr_t)arg, sizeof (int), flag))
953			return (EFAULT);
954
955		return (0);
956	}
957
958	case DKIOCADDBAD:
959		/*
960		 * This is not an update mechanism to add bad blocks
961		 * to the bad block structures stored on disk.
962		 *
963		 * addbadsec(1M) will update the bad block data on disk
964		 * and use this ioctl to force the driver to re-initialize
965		 * the list of bad blocks in the driver.
966		 */
967
968		/* start BBH */
969		cmdk_bbh_reopen(dkp);
970		return (0);
971
972	case DKIOCG_PHYGEOM:
973	case DKIOCG_VIRTGEOM:
974	case DKIOCGGEOM:
975	case DKIOCSGEOM:
976	case DKIOCGAPART:
977	case DKIOCSAPART:
978	case DKIOCGVTOC:
979	case DKIOCSVTOC:
980	case DKIOCPARTINFO:
981	case DKIOCGEXTVTOC:
982	case DKIOCSEXTVTOC:
983	case DKIOCEXTPARTINFO:
984	case DKIOCGMBOOT:
985	case DKIOCSMBOOT:
986	case DKIOCGETEFI:
987	case DKIOCSETEFI:
988	case DKIOCPARTITION:
989	case DKIOCSETEXTPART:
990	{
991		int rc;
992
993		rc = cmlb_ioctl(dkp->dk_cmlbhandle, dev, cmd, arg, flag,
994		    credp, rvalp, 0);
995		if (cmd == DKIOCSVTOC || cmd == DKIOCSEXTVTOC)
996			cmdk_devid_setup(dkp);
997		return (rc);
998	}
999
1000	case DIOCTL_RWCMD: {
1001		struct	dadkio_rwcmd *rwcmdp;
1002		int	status;
1003
1004		rwcmdp = kmem_alloc(sizeof (struct dadkio_rwcmd), KM_SLEEP);
1005
1006		status = rwcmd_copyin(rwcmdp, (caddr_t)arg, flag);
1007
1008		if (status == 0) {
1009			bzero(&(rwcmdp->status), sizeof (struct dadkio_status));
1010			status = dadk_ioctl(DKTP_DATA,
1011			    dev,
1012			    cmd,
1013			    (uintptr_t)rwcmdp,
1014			    flag,
1015			    credp,
1016			    rvalp);
1017		}
1018		if (status == 0)
1019			status = rwcmd_copyout(rwcmdp, (caddr_t)arg, flag);
1020
1021		kmem_free(rwcmdp, sizeof (struct dadkio_rwcmd));
1022		return (status);
1023	}
1024
1025	default:
1026		return (dadk_ioctl(DKTP_DATA,
1027		    dev,
1028		    cmd,
1029		    arg,
1030		    flag,
1031		    credp,
1032		    rvalp));
1033	}
1034}
1035
1036/*ARGSUSED1*/
1037static int
1038cmdkclose(dev_t dev, int flag, int otyp, cred_t *credp)
1039{
1040	int		part;
1041	ulong_t		partbit;
1042	int 		instance;
1043	struct cmdk	*dkp;
1044	int		lastclose = 1;
1045	int		i;
1046
1047	instance = CMDKUNIT(dev);
1048	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) ||
1049	    (otyp >= OTYPCNT))
1050		return (ENXIO);
1051
1052	mutex_enter(&dkp->dk_mutex);
1053
1054	/* check if device has been opened */
1055	ASSERT(cmdk_isopen(dkp, dev));
1056	if (!(dkp->dk_flag & CMDK_OPEN)) {
1057		mutex_exit(&dkp->dk_mutex);
1058		return (ENXIO);
1059	}
1060
1061	while (dkp->dk_flag & CMDK_SUSPEND) {
1062		cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
1063	}
1064
1065	part = CMDKPART(dev);
1066	partbit = 1 << part;
1067
1068	/* account for close */
1069	if (otyp == OTYP_LYR) {
1070		ASSERT(dkp->dk_open_lyr[part] > 0);
1071		if (dkp->dk_open_lyr[part])
1072			dkp->dk_open_lyr[part]--;
1073	} else {
1074		ASSERT((dkp->dk_open_reg[otyp] & partbit) != 0);
1075		dkp->dk_open_reg[otyp] &= ~partbit;
1076	}
1077	dkp->dk_open_exl &= ~partbit;
1078
1079	for (i = 0; i < CMDK_MAXPART; i++)
1080		if (dkp->dk_open_lyr[i] != 0) {
1081			lastclose = 0;
1082			break;
1083		}
1084
1085	if (lastclose)
1086		for (i = 0; i < OTYPCNT; i++)
1087			if (dkp->dk_open_reg[i] != 0) {
1088				lastclose = 0;
1089				break;
1090			}
1091
1092	mutex_exit(&dkp->dk_mutex);
1093
1094	if (lastclose)
1095		cmlb_invalidate(dkp->dk_cmlbhandle, 0);
1096
1097	return (DDI_SUCCESS);
1098}
1099
1100/*ARGSUSED3*/
1101static int
1102cmdkopen(dev_t *dev_p, int flag, int otyp, cred_t *credp)
1103{
1104	dev_t		dev = *dev_p;
1105	int 		part;
1106	ulong_t		partbit;
1107	int 		instance;
1108	struct	cmdk	*dkp;
1109	diskaddr_t	p_lblksrt;
1110	diskaddr_t	p_lblkcnt;
1111	int		i;
1112	int		nodelay;
1113
1114	instance = CMDKUNIT(dev);
1115	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
1116		return (ENXIO);
1117
1118	if (otyp >= OTYPCNT)
1119		return (EINVAL);
1120
1121	mutex_enter(&dkp->dk_mutex);
1122	while (dkp->dk_flag & CMDK_SUSPEND) {
1123		cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
1124	}
1125	mutex_exit(&dkp->dk_mutex);
1126
1127	part = CMDKPART(dev);
1128	partbit = 1 << part;
1129	nodelay = (flag & (FNDELAY | FNONBLOCK));
1130
1131	mutex_enter(&dkp->dk_mutex);
1132
1133	if (cmlb_validate(dkp->dk_cmlbhandle, 0, 0) != 0) {
1134
1135		/* fail if not doing non block open */
1136		if (!nodelay) {
1137			mutex_exit(&dkp->dk_mutex);
1138			return (ENXIO);
1139		}
1140	} else if (cmlb_partinfo(dkp->dk_cmlbhandle, part, &p_lblkcnt,
1141	    &p_lblksrt, NULL, NULL, 0) == 0) {
1142
1143		if (p_lblkcnt <= 0 && (!nodelay || otyp != OTYP_CHR)) {
1144			mutex_exit(&dkp->dk_mutex);
1145			return (ENXIO);
1146		}
1147	} else {
1148		/* fail if not doing non block open */
1149		if (!nodelay) {
1150			mutex_exit(&dkp->dk_mutex);
1151			return (ENXIO);
1152		}
1153	}
1154
1155	if ((DKTP_EXT->tg_rdonly) && (flag & FWRITE)) {
1156		mutex_exit(&dkp->dk_mutex);
1157		return (EROFS);
1158	}
1159
1160	/* check for part already opend exclusively */
1161	if (dkp->dk_open_exl & partbit)
1162		goto excl_open_fail;
1163
1164	/* check if we can establish exclusive open */
1165	if (flag & FEXCL) {
1166		if (dkp->dk_open_lyr[part])
1167			goto excl_open_fail;
1168		for (i = 0; i < OTYPCNT; i++) {
1169			if (dkp->dk_open_reg[i] & partbit)
1170				goto excl_open_fail;
1171		}
1172	}
1173
1174	/* open will succeed, account for open */
1175	dkp->dk_flag |= CMDK_OPEN;
1176	if (otyp == OTYP_LYR)
1177		dkp->dk_open_lyr[part]++;
1178	else
1179		dkp->dk_open_reg[otyp] |= partbit;
1180	if (flag & FEXCL)
1181		dkp->dk_open_exl |= partbit;
1182
1183	mutex_exit(&dkp->dk_mutex);
1184	return (DDI_SUCCESS);
1185
1186excl_open_fail:
1187	mutex_exit(&dkp->dk_mutex);
1188	return (EBUSY);
1189}
1190
1191/*
1192 * read routine
1193 */
1194/*ARGSUSED2*/
1195static int
1196cmdkread(dev_t dev, struct uio *uio, cred_t *credp)
1197{
1198	return (cmdkrw(dev, uio, B_READ));
1199}
1200
1201/*
1202 * async read routine
1203 */
1204/*ARGSUSED2*/
1205static int
1206cmdkaread(dev_t dev, struct aio_req *aio, cred_t *credp)
1207{
1208	return (cmdkarw(dev, aio, B_READ));
1209}
1210
1211/*
1212 * write routine
1213 */
1214/*ARGSUSED2*/
1215static int
1216cmdkwrite(dev_t dev, struct uio *uio, cred_t *credp)
1217{
1218	return (cmdkrw(dev, uio, B_WRITE));
1219}
1220
1221/*
1222 * async write routine
1223 */
1224/*ARGSUSED2*/
1225static int
1226cmdkawrite(dev_t dev, struct aio_req *aio, cred_t *credp)
1227{
1228	return (cmdkarw(dev, aio, B_WRITE));
1229}
1230
1231static void
1232cmdkmin(struct buf *bp)
1233{
1234	if (bp->b_bcount > DK_MAXRECSIZE)
1235		bp->b_bcount = DK_MAXRECSIZE;
1236}
1237
1238static int
1239cmdkrw(dev_t dev, struct uio *uio, int flag)
1240{
1241	int 		instance;
1242	struct	cmdk	*dkp;
1243
1244	instance = CMDKUNIT(dev);
1245	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
1246		return (ENXIO);
1247
1248	mutex_enter(&dkp->dk_mutex);
1249	while (dkp->dk_flag & CMDK_SUSPEND) {
1250		cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
1251	}
1252	mutex_exit(&dkp->dk_mutex);
1253
1254	return (physio(cmdkstrategy, (struct buf *)0, dev, flag, cmdkmin, uio));
1255}
1256
1257static int
1258cmdkarw(dev_t dev, struct aio_req *aio, int flag)
1259{
1260	int 		instance;
1261	struct	cmdk	*dkp;
1262
1263	instance = CMDKUNIT(dev);
1264	if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
1265		return (ENXIO);
1266
1267	mutex_enter(&dkp->dk_mutex);
1268	while (dkp->dk_flag & CMDK_SUSPEND) {
1269		cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
1270	}
1271	mutex_exit(&dkp->dk_mutex);
1272
1273	return (aphysio(cmdkstrategy, anocancel, dev, flag, cmdkmin, aio));
1274}
1275
1276/*
1277 * strategy routine
1278 */
1279static int
1280cmdkstrategy(struct buf *bp)
1281{
1282	int 		instance;
1283	struct	cmdk 	*dkp;
1284	long		d_cnt;
1285	diskaddr_t	p_lblksrt;
1286	diskaddr_t	p_lblkcnt;
1287
1288	instance = CMDKUNIT(bp->b_edev);
1289	if (cmdk_indump || !(dkp = ddi_get_soft_state(cmdk_state, instance)) ||
1290	    (dkblock(bp) < 0)) {
1291		bp->b_resid = bp->b_bcount;
1292		SETBPERR(bp, ENXIO);
1293		biodone(bp);
1294		return (0);
1295	}
1296
1297	mutex_enter(&dkp->dk_mutex);
1298	ASSERT(cmdk_isopen(dkp, bp->b_edev));
1299	while (dkp->dk_flag & CMDK_SUSPEND) {
1300		cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
1301	}
1302	mutex_exit(&dkp->dk_mutex);
1303
1304	bp->b_flags &= ~(B_DONE|B_ERROR);
1305	bp->b_resid = 0;
1306	bp->av_back = NULL;
1307
1308	/*
1309	 * only re-read the vtoc if necessary (force == FALSE)
1310	 */
1311	if (cmlb_partinfo(dkp->dk_cmlbhandle, CMDKPART(bp->b_edev),
1312	    &p_lblkcnt, &p_lblksrt, NULL, NULL, 0)) {
1313		SETBPERR(bp, ENXIO);
1314	}
1315
1316	if ((bp->b_bcount & (NBPSCTR-1)) || (dkblock(bp) > p_lblkcnt))
1317		SETBPERR(bp, ENXIO);
1318
1319	if ((bp->b_flags & B_ERROR) || (dkblock(bp) == p_lblkcnt)) {
1320		bp->b_resid = bp->b_bcount;
1321		biodone(bp);
1322		return (0);
1323	}
1324
1325	d_cnt = bp->b_bcount >> SCTRSHFT;
1326	if ((dkblock(bp) + d_cnt) > p_lblkcnt) {
1327		bp->b_resid = ((dkblock(bp) + d_cnt) - p_lblkcnt) << SCTRSHFT;
1328		bp->b_bcount -= bp->b_resid;
1329	}
1330
1331	SET_BP_SEC(bp, ((ulong_t)(p_lblksrt + dkblock(bp))));
1332	if (dadk_strategy(DKTP_DATA, bp) != DDI_SUCCESS) {
1333		bp->b_resid += bp->b_bcount;
1334		biodone(bp);
1335	}
1336	return (0);
1337}
1338
1339static int
1340cmdk_create_obj(dev_info_t *dip, struct cmdk *dkp)
1341{
1342	struct scsi_device *devp;
1343	opaque_t	queobjp = NULL;
1344	opaque_t	flcobjp = NULL;
1345	char		que_keyvalp[64];
1346	int		que_keylen;
1347	char		flc_keyvalp[64];
1348	int		flc_keylen;
1349
1350	ASSERT(mutex_owned(&dkp->dk_mutex));
1351
1352	/* Create linkage to queueing routines based on property */
1353	que_keylen = sizeof (que_keyvalp);
1354	if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF,
1355	    DDI_PROP_CANSLEEP, "queue", que_keyvalp, &que_keylen) !=
1356	    DDI_PROP_SUCCESS) {
1357		cmn_err(CE_WARN, "cmdk_create_obj: queue property undefined");
1358		return (DDI_FAILURE);
1359	}
1360	que_keyvalp[que_keylen] = (char)0;
1361
1362	if (strcmp(que_keyvalp, "qfifo") == 0) {
1363		queobjp = (opaque_t)qfifo_create();
1364	} else if (strcmp(que_keyvalp, "qsort") == 0) {
1365		queobjp = (opaque_t)qsort_create();
1366	} else {
1367		return (DDI_FAILURE);
1368	}
1369
1370	/* Create linkage to dequeueing routines based on property */
1371	flc_keylen = sizeof (flc_keyvalp);
1372	if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF,
1373	    DDI_PROP_CANSLEEP, "flow_control", flc_keyvalp, &flc_keylen) !=
1374	    DDI_PROP_SUCCESS) {
1375		cmn_err(CE_WARN,
1376		    "cmdk_create_obj: flow-control property undefined");
1377		return (DDI_FAILURE);
1378	}
1379
1380	flc_keyvalp[flc_keylen] = (char)0;
1381
1382	if (strcmp(flc_keyvalp, "dsngl") == 0) {
1383		flcobjp = (opaque_t)dsngl_create();
1384	} else if (strcmp(flc_keyvalp, "dmult") == 0) {
1385		flcobjp = (opaque_t)dmult_create();
1386	} else {
1387		return (DDI_FAILURE);
1388	}
1389
1390	/* populate bbh_obj object stored in dkp */
1391	dkp->dk_bbh_obj.bbh_data = dkp;
1392	dkp->dk_bbh_obj.bbh_ops = &cmdk_bbh_ops;
1393
1394	/* create linkage to dadk */
1395	dkp->dk_tgobjp = (opaque_t)dadk_create();
1396
1397	devp = ddi_get_driver_private(dip);
1398	(void) dadk_init(DKTP_DATA, devp, flcobjp, queobjp, &dkp->dk_bbh_obj,
1399	    NULL);
1400
1401	return (DDI_SUCCESS);
1402}
1403
1404static void
1405cmdk_destroy_obj(dev_info_t *dip, struct cmdk *dkp)
1406{
1407	char		que_keyvalp[64];
1408	int		que_keylen;
1409	char		flc_keyvalp[64];
1410	int		flc_keylen;
1411
1412	ASSERT(mutex_owned(&dkp->dk_mutex));
1413
1414	(void) dadk_free((dkp->dk_tgobjp));
1415	dkp->dk_tgobjp = NULL;
1416
1417	que_keylen = sizeof (que_keyvalp);
1418	if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF,
1419	    DDI_PROP_CANSLEEP, "queue", que_keyvalp, &que_keylen) !=
1420	    DDI_PROP_SUCCESS) {
1421		cmn_err(CE_WARN, "cmdk_destroy_obj: queue property undefined");
1422		return;
1423	}
1424	que_keyvalp[que_keylen] = (char)0;
1425
1426	flc_keylen = sizeof (flc_keyvalp);
1427	if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF,
1428	    DDI_PROP_CANSLEEP, "flow_control", flc_keyvalp, &flc_keylen) !=
1429	    DDI_PROP_SUCCESS) {
1430		cmn_err(CE_WARN,
1431		    "cmdk_destroy_obj: flow-control property undefined");
1432		return;
1433	}
1434	flc_keyvalp[flc_keylen] = (char)0;
1435}
1436/*ARGSUSED5*/
1437static int
1438cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr,
1439    diskaddr_t start, size_t count, void *tg_cookie)
1440{
1441	struct cmdk	*dkp;
1442	opaque_t	handle;
1443	int		rc = 0;
1444	char		*bufa;
1445	size_t		buflen;
1446
1447	dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip));
1448	if (dkp == NULL)
1449		return (ENXIO);
1450
1451	if (cmd != TG_READ && cmd != TG_WRITE)
1452		return (EINVAL);
1453
1454	/* buflen must be multiple of 512 */
1455	buflen = (count + NBPSCTR - 1) & -NBPSCTR;
1456	handle = dadk_iob_alloc(DKTP_DATA, start, buflen, KM_SLEEP);
1457	if (!handle)
1458		return (ENOMEM);
1459
1460	if (cmd == TG_READ) {
1461		bufa = dadk_iob_xfer(DKTP_DATA, handle, B_READ);
1462		if (!bufa)
1463			rc = EIO;
1464		else
1465			bcopy(bufa, bufaddr, count);
1466	} else {
1467		bufa = dadk_iob_htoc(DKTP_DATA, handle);
1468		bcopy(bufaddr, bufa, count);
1469		bufa = dadk_iob_xfer(DKTP_DATA, handle, B_WRITE);
1470		if (!bufa)
1471			rc = EIO;
1472	}
1473	(void) dadk_iob_free(DKTP_DATA, handle);
1474
1475	return (rc);
1476}
1477
1478/*ARGSUSED3*/
1479static int
1480cmdk_lb_getinfo(dev_info_t *dip, int cmd, void *arg, void *tg_cookie)
1481{
1482
1483	struct cmdk		*dkp;
1484	struct tgdk_geom	phyg;
1485
1486
1487	dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip));
1488	if (dkp == NULL)
1489		return (ENXIO);
1490
1491	switch (cmd) {
1492	case TG_GETPHYGEOM: {
1493		cmlb_geom_t *phygeomp = (cmlb_geom_t *)arg;
1494
1495		/* dadk_getphygeom always returns success */
1496		(void) dadk_getphygeom(DKTP_DATA, &phyg);
1497
1498		phygeomp->g_capacity	= phyg.g_cap;
1499		phygeomp->g_nsect	= phyg.g_sec;
1500		phygeomp->g_nhead	= phyg.g_head;
1501		phygeomp->g_acyl	= phyg.g_acyl;
1502		phygeomp->g_ncyl	= phyg.g_cyl;
1503		phygeomp->g_secsize	= phyg.g_secsiz;
1504		phygeomp->g_intrlv	= 1;
1505		phygeomp->g_rpm		= 3600;
1506
1507		return (0);
1508	}
1509
1510	case TG_GETVIRTGEOM: {
1511		cmlb_geom_t *virtgeomp = (cmlb_geom_t *)arg;
1512		diskaddr_t		capacity;
1513
1514		(void) dadk_getgeom(DKTP_DATA, &phyg);
1515		capacity = phyg.g_cap;
1516
1517		/*
1518		 * If the controller returned us something that doesn't
1519		 * really fit into an Int 13/function 8 geometry
1520		 * result, just fail the ioctl.  See PSARC 1998/313.
1521		 */
1522		if (capacity < 0 || capacity >= 63 * 254 * 1024)
1523			return (EINVAL);
1524
1525		virtgeomp->g_capacity	= capacity;
1526		virtgeomp->g_nsect	= 63;
1527		virtgeomp->g_nhead	= 254;
1528		virtgeomp->g_ncyl	= capacity / (63 * 254);
1529		virtgeomp->g_acyl	= 0;
1530		virtgeomp->g_secsize	= 512;
1531		virtgeomp->g_intrlv	= 1;
1532		virtgeomp->g_rpm	= 3600;
1533
1534		return (0);
1535	}
1536
1537	case TG_GETCAPACITY:
1538	case TG_GETBLOCKSIZE:
1539	{
1540
1541		/* dadk_getphygeom always returns success */
1542		(void) dadk_getphygeom(DKTP_DATA, &phyg);
1543		if (cmd == TG_GETCAPACITY)
1544			*(diskaddr_t *)arg = phyg.g_cap;
1545		else
1546			*(uint32_t *)arg = (uint32_t)phyg.g_secsiz;
1547
1548		return (0);
1549	}
1550
1551	case TG_GETATTR: {
1552		tg_attribute_t *tgattribute = (tg_attribute_t *)arg;
1553		if ((DKTP_EXT->tg_rdonly))
1554			tgattribute->media_is_writable = FALSE;
1555		else
1556			tgattribute->media_is_writable = TRUE;
1557		tgattribute->media_is_rotational = TRUE;
1558
1559		return (0);
1560	}
1561
1562	default:
1563		return (ENOTTY);
1564	}
1565}
1566
1567
1568
1569
1570
1571/*
1572 * Create and register the devid.
1573 * There are 4 different ways we can get a device id:
1574 *    1. Already have one - nothing to do
1575 *    2. Build one from the drive's model and serial numbers
1576 *    3. Read one from the disk (first sector of last track)
1577 *    4. Fabricate one and write it on the disk.
1578 * If any of these succeeds, register the deviceid
1579 */
1580static void
1581cmdk_devid_setup(struct cmdk *dkp)
1582{
1583	int	rc;
1584
1585	/* Try options until one succeeds, or all have failed */
1586
1587	/* 1. All done if already registered */
1588	if (dkp->dk_devid != NULL)
1589		return;
1590
1591	/* 2. Build a devid from the model and serial number */
1592	rc = cmdk_devid_modser(dkp);
1593	if (rc != DDI_SUCCESS) {
1594		/* 3. Read devid from the disk, if present */
1595		rc = cmdk_devid_read(dkp);
1596
1597		/* 4. otherwise make one up and write it on the disk */
1598		if (rc != DDI_SUCCESS)
1599			rc = cmdk_devid_fabricate(dkp);
1600	}
1601
1602	/* If we managed to get a devid any of the above ways, register it */
1603	if (rc == DDI_SUCCESS)
1604		(void) ddi_devid_register(dkp->dk_dip, dkp->dk_devid);
1605
1606}
1607
1608/*
1609 * Build a devid from the model and serial number
1610 * Return DDI_SUCCESS or DDI_FAILURE.
1611 */
1612static int
1613cmdk_devid_modser(struct cmdk *dkp)
1614{
1615	int	rc = DDI_FAILURE;
1616	char	*hwid;
1617	int	modlen;
1618	int	serlen;
1619
1620	/*
1621	 * device ID is a concatenation of model number, '=', serial number.
1622	 */
1623	hwid = kmem_alloc(CMDK_HWIDLEN, KM_SLEEP);
1624	modlen = cmdk_get_modser(dkp, DIOCTL_GETMODEL, hwid, CMDK_HWIDLEN);
1625	if (modlen == 0) {
1626		rc = DDI_FAILURE;
1627		goto err;
1628	}
1629	hwid[modlen++] = '=';
1630	serlen = cmdk_get_modser(dkp, DIOCTL_GETSERIAL,
1631	    hwid + modlen, CMDK_HWIDLEN - modlen);
1632	if (serlen == 0) {
1633		rc = DDI_FAILURE;
1634		goto err;
1635	}
1636	hwid[modlen + serlen] = 0;
1637
1638	/* Initialize the device ID, trailing NULL not included */
1639	rc = ddi_devid_init(dkp->dk_dip, DEVID_ATA_SERIAL, modlen + serlen,
1640	    hwid, &dkp->dk_devid);
1641	if (rc != DDI_SUCCESS) {
1642		rc = DDI_FAILURE;
1643		goto err;
1644	}
1645
1646	rc = DDI_SUCCESS;
1647
1648err:
1649	kmem_free(hwid, CMDK_HWIDLEN);
1650	return (rc);
1651}
1652
1653static int
1654cmdk_get_modser(struct cmdk *dkp, int ioccmd, char *buf, int len)
1655{
1656	dadk_ioc_string_t strarg;
1657	int		rval;
1658	char		*s;
1659	char		ch;
1660	boolean_t	ret;
1661	int		i;
1662	int		tb;
1663
1664	strarg.is_buf = buf;
1665	strarg.is_size = len;
1666	if (dadk_ioctl(DKTP_DATA,
1667	    dkp->dk_dev,
1668	    ioccmd,
1669	    (uintptr_t)&strarg,
1670	    FNATIVE | FKIOCTL,
1671	    NULL,
1672	    &rval) != 0)
1673		return (0);
1674
1675	/*
1676	 * valid model/serial string must contain a non-zero non-space
1677	 * trim trailing spaces/NULL
1678	 */
1679	ret = B_FALSE;
1680	s = buf;
1681	for (i = 0; i < strarg.is_size; i++) {
1682		ch = *s++;
1683		if (ch != ' ' && ch != '\0')
1684			tb = i + 1;
1685		if (ch != ' ' && ch != '\0' && ch != '0')
1686			ret = B_TRUE;
1687	}
1688
1689	if (ret == B_FALSE)
1690		return (0);
1691
1692	return (tb);
1693}
1694
1695/*
1696 * Read a devid from on the first block of the last track of
1697 * the last cylinder.  Make sure what we read is a valid devid.
1698 * Return DDI_SUCCESS or DDI_FAILURE.
1699 */
1700static int
1701cmdk_devid_read(struct cmdk *dkp)
1702{
1703	diskaddr_t	blk;
1704	struct dk_devid *dkdevidp;
1705	uint_t		*ip;
1706	int		chksum;
1707	int		i, sz;
1708	tgdk_iob_handle	handle = NULL;
1709	int		rc = DDI_FAILURE;
1710
1711	if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0))
1712		goto err;
1713
1714	/* read the devid */
1715	handle = dadk_iob_alloc(DKTP_DATA, blk, NBPSCTR, KM_SLEEP);
1716	if (handle == NULL)
1717		goto err;
1718
1719	dkdevidp = (struct dk_devid *)dadk_iob_xfer(DKTP_DATA, handle, B_READ);
1720	if (dkdevidp == NULL)
1721		goto err;
1722
1723	/* Validate the revision */
1724	if ((dkdevidp->dkd_rev_hi != DK_DEVID_REV_MSB) ||
1725	    (dkdevidp->dkd_rev_lo != DK_DEVID_REV_LSB))
1726		goto err;
1727
1728	/* Calculate the checksum */
1729	chksum = 0;
1730	ip = (uint_t *)dkdevidp;
1731	for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++)
1732		chksum ^= ip[i];
1733	if (DKD_GETCHKSUM(dkdevidp) != chksum)
1734		goto err;
1735
1736	/* Validate the device id */
1737	if (ddi_devid_valid((ddi_devid_t)dkdevidp->dkd_devid) != DDI_SUCCESS)
1738		goto err;
1739
1740	/* keep a copy of the device id */
1741	sz = ddi_devid_sizeof((ddi_devid_t)dkdevidp->dkd_devid);
1742	dkp->dk_devid = kmem_alloc(sz, KM_SLEEP);
1743	bcopy(dkdevidp->dkd_devid, dkp->dk_devid, sz);
1744
1745	rc = DDI_SUCCESS;
1746
1747err:
1748	if (handle != NULL)
1749		(void) dadk_iob_free(DKTP_DATA, handle);
1750	return (rc);
1751}
1752
1753/*
1754 * Create a devid and write it on the first block of the last track of
1755 * the last cylinder.
1756 * Return DDI_SUCCESS or DDI_FAILURE.
1757 */
1758static int
1759cmdk_devid_fabricate(struct cmdk *dkp)
1760{
1761	ddi_devid_t	devid = NULL;	/* devid made by ddi_devid_init  */
1762	struct dk_devid	*dkdevidp;	/* devid struct stored on disk */
1763	diskaddr_t	blk;
1764	tgdk_iob_handle	handle = NULL;
1765	uint_t		*ip, chksum;
1766	int		i;
1767	int		rc = DDI_FAILURE;
1768
1769	if (ddi_devid_init(dkp->dk_dip, DEVID_FAB, 0, NULL, &devid) !=
1770	    DDI_SUCCESS)
1771		goto err;
1772
1773	if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0)) {
1774		/* no device id block address */
1775		goto err;
1776	}
1777
1778	handle = dadk_iob_alloc(DKTP_DATA, blk, NBPSCTR, KM_SLEEP);
1779	if (!handle)
1780		goto err;
1781
1782	/* Locate the buffer */
1783	dkdevidp = (struct dk_devid *)dadk_iob_htoc(DKTP_DATA, handle);
1784
1785	/* Fill in the revision */
1786	bzero(dkdevidp, NBPSCTR);
1787	dkdevidp->dkd_rev_hi = DK_DEVID_REV_MSB;
1788	dkdevidp->dkd_rev_lo = DK_DEVID_REV_LSB;
1789
1790	/* Copy in the device id */
1791	i = ddi_devid_sizeof(devid);
1792	if (i > DK_DEVID_SIZE)
1793		goto err;
1794	bcopy(devid, dkdevidp->dkd_devid, i);
1795
1796	/* Calculate the chksum */
1797	chksum = 0;
1798	ip = (uint_t *)dkdevidp;
1799	for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++)
1800		chksum ^= ip[i];
1801
1802	/* Fill in the checksum */
1803	DKD_FORMCHKSUM(chksum, dkdevidp);
1804
1805	/* write the devid */
1806	(void) dadk_iob_xfer(DKTP_DATA, handle, B_WRITE);
1807
1808	dkp->dk_devid = devid;
1809
1810	rc = DDI_SUCCESS;
1811
1812err:
1813	if (handle != NULL)
1814		(void) dadk_iob_free(DKTP_DATA, handle);
1815
1816	if (rc != DDI_SUCCESS && devid != NULL)
1817		ddi_devid_free(devid);
1818
1819	return (rc);
1820}
1821
1822static void
1823cmdk_bbh_free_alts(struct cmdk *dkp)
1824{
1825	if (dkp->dk_alts_hdl) {
1826		(void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl);
1827		kmem_free(dkp->dk_slc_cnt,
1828		    NDKMAP * (sizeof (uint32_t) + sizeof (struct alts_ent *)));
1829		dkp->dk_alts_hdl = NULL;
1830	}
1831}
1832
1833static void
1834cmdk_bbh_reopen(struct cmdk *dkp)
1835{
1836	tgdk_iob_handle 	handle = NULL;
1837	diskaddr_t		slcb, slcn, slce;
1838	struct	alts_parttbl	*ap;
1839	struct	alts_ent	*enttblp;
1840	uint32_t		altused;
1841	uint32_t		altbase;
1842	uint32_t		altlast;
1843	int			alts;
1844	uint16_t		vtoctag;
1845	int			i, j;
1846
1847	/* find slice with V_ALTSCTR tag */
1848	for (alts = 0; alts < NDKMAP; alts++) {
1849		if (cmlb_partinfo(
1850		    dkp->dk_cmlbhandle,
1851		    alts,
1852		    &slcn,
1853		    &slcb,
1854		    NULL,
1855		    &vtoctag,
1856		    0)) {
1857			goto empty;	/* no partition table exists */
1858		}
1859
1860		if (vtoctag == V_ALTSCTR && slcn > 1)
1861			break;
1862	}
1863	if (alts >= NDKMAP) {
1864		goto empty;	/* no V_ALTSCTR slice defined */
1865	}
1866
1867	/* read in ALTS label block */
1868	handle = dadk_iob_alloc(DKTP_DATA, slcb, NBPSCTR, KM_SLEEP);
1869	if (!handle) {
1870		goto empty;
1871	}
1872
1873	ap = (struct alts_parttbl *)dadk_iob_xfer(DKTP_DATA, handle, B_READ);
1874	if (!ap || (ap->alts_sanity != ALTS_SANITY)) {
1875		goto empty;
1876	}
1877
1878	altused = ap->alts_ent_used;	/* number of BB entries */
1879	altbase = ap->alts_ent_base;	/* blk offset from begin slice */
1880	altlast = ap->alts_ent_end;	/* blk offset to last block */
1881	/* ((altused * sizeof (struct alts_ent) + NBPSCTR - 1) & ~NBPSCTR) */
1882
1883	if (altused == 0 ||
1884	    altbase < 1 ||
1885	    altbase > altlast ||
1886	    altlast >= slcn) {
1887		goto empty;
1888	}
1889	(void) dadk_iob_free(DKTP_DATA, handle);
1890
1891	/* read in ALTS remapping table */
1892	handle = dadk_iob_alloc(DKTP_DATA,
1893	    slcb + altbase,
1894	    (altlast - altbase + 1) << SCTRSHFT, KM_SLEEP);
1895	if (!handle) {
1896		goto empty;
1897	}
1898
1899	enttblp = (struct alts_ent *)dadk_iob_xfer(DKTP_DATA, handle, B_READ);
1900	if (!enttblp) {
1901		goto empty;
1902	}
1903
1904	rw_enter(&dkp->dk_bbh_mutex, RW_WRITER);
1905
1906	/* allocate space for dk_slc_cnt and dk_slc_ent tables */
1907	if (dkp->dk_slc_cnt == NULL) {
1908		dkp->dk_slc_cnt = kmem_alloc(NDKMAP *
1909		    (sizeof (long) + sizeof (struct alts_ent *)), KM_SLEEP);
1910	}
1911	dkp->dk_slc_ent = (struct alts_ent **)(dkp->dk_slc_cnt + NDKMAP);
1912
1913	/* free previous BB table (if any) */
1914	if (dkp->dk_alts_hdl) {
1915		(void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl);
1916		dkp->dk_alts_hdl = NULL;
1917		dkp->dk_altused = 0;
1918	}
1919
1920	/* save linkage to new BB table */
1921	dkp->dk_alts_hdl = handle;
1922	dkp->dk_altused = altused;
1923
1924	/*
1925	 * build indexes to BB table by slice
1926	 * effectively we have
1927	 *	struct alts_ent *enttblp[altused];
1928	 *
1929	 *	uint32_t	dk_slc_cnt[NDKMAP];
1930	 *	struct alts_ent *dk_slc_ent[NDKMAP];
1931	 */
1932	for (i = 0; i < NDKMAP; i++) {
1933		if (cmlb_partinfo(
1934		    dkp->dk_cmlbhandle,
1935		    i,
1936		    &slcn,
1937		    &slcb,
1938		    NULL,
1939		    NULL,
1940		    0)) {
1941			goto empty1;
1942		}
1943
1944		dkp->dk_slc_cnt[i] = 0;
1945		if (slcn == 0)
1946			continue;	/* slice is not allocated */
1947
1948		/* last block in slice */
1949		slce = slcb + slcn - 1;
1950
1951		/* find first remap entry in after beginnning of slice */
1952		for (j = 0; j < altused; j++) {
1953			if (enttblp[j].bad_start + enttblp[j].bad_end >= slcb)
1954				break;
1955		}
1956		dkp->dk_slc_ent[i] = enttblp + j;
1957
1958		/* count remap entrys until end of slice */
1959		for (; j < altused && enttblp[j].bad_start <= slce; j++) {
1960			dkp->dk_slc_cnt[i] += 1;
1961		}
1962	}
1963
1964	rw_exit(&dkp->dk_bbh_mutex);
1965	return;
1966
1967empty:
1968	rw_enter(&dkp->dk_bbh_mutex, RW_WRITER);
1969empty1:
1970	if (handle && handle != dkp->dk_alts_hdl)
1971		(void) dadk_iob_free(DKTP_DATA, handle);
1972
1973	if (dkp->dk_alts_hdl) {
1974		(void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl);
1975		dkp->dk_alts_hdl = NULL;
1976	}
1977
1978	rw_exit(&dkp->dk_bbh_mutex);
1979}
1980
1981/*ARGSUSED*/
1982static bbh_cookie_t
1983cmdk_bbh_htoc(opaque_t bbh_data, opaque_t handle)
1984{
1985	struct	bbh_handle *hp;
1986	bbh_cookie_t ckp;
1987
1988	hp = (struct  bbh_handle *)handle;
1989	ckp = hp->h_cktab + hp->h_idx;
1990	hp->h_idx++;
1991	return (ckp);
1992}
1993
1994/*ARGSUSED*/
1995static void
1996cmdk_bbh_freehandle(opaque_t bbh_data, opaque_t handle)
1997{
1998	struct	bbh_handle *hp;
1999
2000	hp = (struct  bbh_handle *)handle;
2001	kmem_free(handle, (sizeof (struct bbh_handle) +
2002	    (hp->h_totck * (sizeof (struct bbh_cookie)))));
2003}
2004
2005
2006/*
2007 *	cmdk_bbh_gethandle remaps the bad sectors to alternates.
2008 *	There are 7 different cases when the comparison is made
2009 *	between the bad sector cluster and the disk section.
2010 *
2011 *	bad sector cluster	gggggggggggbbbbbbbggggggggggg
2012 *	case 1:			   ddddd
2013 *	case 2:				   -d-----
2014 *	case 3:					     ddddd
2015 *	case 4:			         dddddddddddd
2016 *	case 5:			      ddddddd-----
2017 *	case 6:			           ---ddddddd
2018 *	case 7:			           ddddddd
2019 *
2020 *	where:  g = good sector,	b = bad sector
2021 *		d = sector in disk section
2022 *		- = disk section may be extended to cover those disk area
2023 */
2024
2025static opaque_t
2026cmdk_bbh_gethandle(opaque_t bbh_data, struct buf *bp)
2027{
2028	struct cmdk		*dkp = (struct cmdk *)bbh_data;
2029	struct bbh_handle	*hp;
2030	struct bbh_cookie	*ckp;
2031	struct alts_ent		*altp;
2032	uint32_t		alts_used;
2033	uint32_t		part = CMDKPART(bp->b_edev);
2034	daddr32_t		lastsec;
2035	long			d_count;
2036	int			i;
2037	int			idx;
2038	int			cnt;
2039
2040	if (part >= V_NUMPAR)
2041		return (NULL);
2042
2043	/*
2044	 * This if statement is atomic and it will succeed
2045	 * if there are no bad blocks (almost always)
2046	 *
2047	 * so this if is performed outside of the rw_enter for speed
2048	 * and then repeated inside the rw_enter for safety
2049	 */
2050	if (!dkp->dk_alts_hdl) {
2051		return (NULL);
2052	}
2053
2054	rw_enter(&dkp->dk_bbh_mutex, RW_READER);
2055
2056	if (dkp->dk_alts_hdl == NULL) {
2057		rw_exit(&dkp->dk_bbh_mutex);
2058		return (NULL);
2059	}
2060
2061	alts_used = dkp->dk_slc_cnt[part];
2062	if (alts_used == 0) {
2063		rw_exit(&dkp->dk_bbh_mutex);
2064		return (NULL);
2065	}
2066	altp = dkp->dk_slc_ent[part];
2067
2068	/*
2069	 * binary search for the largest bad sector index in the alternate
2070	 * entry table which overlaps or larger than the starting d_sec
2071	 */
2072	i = cmdk_bbh_bsearch(altp, alts_used, GET_BP_SEC(bp));
2073	/* if starting sector is > the largest bad sector, return */
2074	if (i == -1) {
2075		rw_exit(&dkp->dk_bbh_mutex);
2076		return (NULL);
2077	}
2078	/* i is the starting index.  Set altp to the starting entry addr */
2079	altp += i;
2080
2081	d_count = bp->b_bcount >> SCTRSHFT;
2082	lastsec = GET_BP_SEC(bp) + d_count - 1;
2083
2084	/* calculate the number of bad sectors */
2085	for (idx = i, cnt = 0; idx < alts_used; idx++, altp++, cnt++) {
2086		if (lastsec < altp->bad_start)
2087			break;
2088	}
2089
2090	if (!cnt) {
2091		rw_exit(&dkp->dk_bbh_mutex);
2092		return (NULL);
2093	}
2094
2095	/* calculate the maximum number of reserved cookies */
2096	cnt <<= 1;
2097	cnt++;
2098
2099	/* allocate the handle */
2100	hp = (struct bbh_handle *)kmem_zalloc((sizeof (*hp) +
2101	    (cnt * sizeof (*ckp))), KM_SLEEP);
2102
2103	hp->h_idx = 0;
2104	hp->h_totck = cnt;
2105	ckp = hp->h_cktab = (struct bbh_cookie *)(hp + 1);
2106	ckp[0].ck_sector = GET_BP_SEC(bp);
2107	ckp[0].ck_seclen = d_count;
2108
2109	altp = dkp->dk_slc_ent[part];
2110	altp += i;
2111	for (idx = 0; i < alts_used; i++, altp++) {
2112		/* CASE 1: */
2113		if (lastsec < altp->bad_start)
2114			break;
2115
2116		/* CASE 3: */
2117		if (ckp[idx].ck_sector > altp->bad_end)
2118			continue;
2119
2120		/* CASE 2 and 7: */
2121		if ((ckp[idx].ck_sector >= altp->bad_start) &&
2122		    (lastsec <= altp->bad_end)) {
2123			ckp[idx].ck_sector = altp->good_start +
2124			    ckp[idx].ck_sector - altp->bad_start;
2125			break;
2126		}
2127
2128		/* at least one bad sector in our section.  break it. */
2129		/* CASE 5: */
2130		if ((lastsec >= altp->bad_start) &&
2131		    (lastsec <= altp->bad_end)) {
2132			ckp[idx+1].ck_seclen = lastsec - altp->bad_start + 1;
2133			ckp[idx].ck_seclen -= ckp[idx+1].ck_seclen;
2134			ckp[idx+1].ck_sector = altp->good_start;
2135			break;
2136		}
2137		/* CASE 6: */
2138		if ((ckp[idx].ck_sector <= altp->bad_end) &&
2139		    (ckp[idx].ck_sector >= altp->bad_start)) {
2140			ckp[idx+1].ck_seclen = ckp[idx].ck_seclen;
2141			ckp[idx].ck_seclen = altp->bad_end -
2142			    ckp[idx].ck_sector + 1;
2143			ckp[idx+1].ck_seclen -= ckp[idx].ck_seclen;
2144			ckp[idx].ck_sector = altp->good_start +
2145			    ckp[idx].ck_sector - altp->bad_start;
2146			idx++;
2147			ckp[idx].ck_sector = altp->bad_end + 1;
2148			continue;	/* check rest of section */
2149		}
2150
2151		/* CASE 4: */
2152		ckp[idx].ck_seclen = altp->bad_start - ckp[idx].ck_sector;
2153		ckp[idx+1].ck_sector = altp->good_start;
2154		ckp[idx+1].ck_seclen = altp->bad_end - altp->bad_start + 1;
2155		idx += 2;
2156		ckp[idx].ck_sector = altp->bad_end + 1;
2157		ckp[idx].ck_seclen = lastsec - altp->bad_end;
2158	}
2159
2160	rw_exit(&dkp->dk_bbh_mutex);
2161	return ((opaque_t)hp);
2162}
2163
2164static int
2165cmdk_bbh_bsearch(struct alts_ent *buf, int cnt, daddr32_t key)
2166{
2167	int	i;
2168	int	ind;
2169	int	interval;
2170	int	mystatus = -1;
2171
2172	if (!cnt)
2173		return (mystatus);
2174
2175	ind = 1; /* compiler complains about possible uninitialized var	*/
2176	for (i = 1; i <= cnt; i <<= 1)
2177		ind = i;
2178
2179	for (interval = ind; interval; ) {
2180		if ((key >= buf[ind-1].bad_start) &&
2181		    (key <= buf[ind-1].bad_end)) {
2182			return (ind-1);
2183		} else {
2184			interval >>= 1;
2185			if (key < buf[ind-1].bad_start) {
2186				/* record the largest bad sector index */
2187				mystatus = ind-1;
2188				if (!interval)
2189					break;
2190				ind = ind - interval;
2191			} else {
2192				/*
2193				 * if key is larger than the last element
2194				 * then break
2195				 */
2196				if ((ind == cnt) || !interval)
2197					break;
2198				if ((ind+interval) <= cnt)
2199					ind += interval;
2200			}
2201		}
2202	}
2203	return (mystatus);
2204}
2205