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