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